View Issue Details

IDProjectCategoryView StatusLast Update
0001791T99X171.00 SKB EagleVOCpublic2023-12-27 14:13
Reporter(ALTech) JunGyu Kim Assigned To(ALTech) Younkwang Jung Due Date2023-08-24 17:56
PrioritynormalSeveritys4-minorReproducibilityrandom
Status closedResolutionfixed 
Summary0001791: [Smart3][ATV10] Audio is choppy after connect earphone to BA01 RCU while playing youtube
DescriptionHi Kerwin,

The issue was reported by end user.
Audio is choppy after connect earphone to BA01 RCU while playing youtube.

Jira ticket : https://jira.skbroadband.com/browse/BTVV-6562

FW : 15.536.26
BA01 RCU version : S.W 01.40
YouTube version : 3.05.003

I checked the logs and AudioTrack log is repeating.

========================================================================
main.log.4:6021:08-10 19:31:01.140 6938 8870 W AudioTrack: getTimestamp_l(60): retrograde timestamp position corrected, -104 = 1162373 - 1162477
main.log.4:6030:08-10 19:31:01.232 6938 8870 W AudioTrack: getTimestamp_l(60): retrograde timestamp position corrected, -103 = 1166599 - 1166702
main.log.4:6051:08-10 19:31:01.520 6938 8870 W AudioTrack: getTimestamp_l(60): retrograde timestamp position corrected, -492 = 1178889 - 1179381
main.log.4:6077:08-10 19:31:01.919 6938 8870 W AudioTrack: getTimestamp_l(60): retrograde timestamp position corrected, -172 = 1197317 - 1197489
main.log.4:6088:08-10 19:31:02.115 6938 8870 W AudioTrack: getTimestamp_l(60): retrograde timestamp position corrected, -495 = 1205381 - 1205876
main.log.4:6103:08-10 19:31:02.393 6938 8870 W AudioTrack: getTimestamp_l(60): retrograde timestamp position corrected, -485 = 1217672 - 1218157
========================================================================

We are trying to reproduce this issue and can reproduce sometimes. But reporduce step is not clear.
I will let you know when the reproduce step is clear.
Please check this issue.

Thank you.
Kim
TagsNo tags attached.
Attach Tags

Users monitoring this issue

Activities

(ALTech) JunGyu Kim

2023-08-17 17:06

developer  

BTVV-6562.zip (1,951,952 bytes)

(ALTech) Younkwang Jung

2023-08-22 08:09

developer   ~0013930

Hi Sam Yang

Please update the progress

Thank you
YK.Jung

(SW) Jason Ling

2023-08-22 12:21

developer   ~0013935

Hi YK,

>>We are trying to reproduce this issue and can reproduce sometimes. But reporduce step is not clear.
>>I will let you know when the reproduce step is clear.

Have you found the reproduce step?

Thanks,
Jason

(ALTech) JunGyu Kim

2023-08-22 13:29

developer   ~0013936

Hi Jason,

We are trying to found reproduce step but it seems randomly.
I think you can reproduce this issue your side.
Have you tried reproducing this issue?

Also, please check what is the cause of the log.

Thank you.
Kim

(ALTech) Younkwang Jung

2023-08-28 09:28

developer   ~0013997

Hi Sam Yang

Please update the progress

Thank you
YK.Jung

(SW) Sam Yang

2023-08-29 11:16

developer   ~0014013

Hi Younkwang,

I test the eagle12 newest FW, and don't find the same issue. So I am checking the different commits between 10 and 12.
And if you have tested the 12 FW, please let me know the result.

Thanks~
Sam

(ALTech) Younkwang Jung

2023-09-06 10:20

developer   ~0014085

Hi Sam

I wasn't observed on ATV12, either. But I will check more when I have time.
Did you find the cause?
Please update us on the current progress.

Thank you
YK.Jung

(SW) Sam Yang

2023-09-06 10:22

developer   ~0014086

Hi Younkwang,

I tried these FWs "0504_536r33_at100", "0718_536r37_at100" for 40 times each, but can't reproduce the issue.
My test steps are:
1.connect RCU a2dp earphone
2.play YT content
3.plug out a2dp and output sound from HDMI
4.plug in a2dp and output sound from a2dp
5.redo 3 & 4 loop
Could you retry with the newest FW to verify again?

Thanks~~
Sam

(ALTech) JunGyu Kim

2023-09-06 19:27

developer   ~0014098

Hi Sam,

I tried some FWs and I can reproduce this issue with below log.
v15.536.26 -> ATV 10
v15.540.16 -> ATV 10
v15.537.62 -> ATV 12
=======================================================
09-06 20:10:12.233 10667 11003 W AudioTrack: getTimestamp_l(30): retrograde timestamp position corrected, -109 = 3177866 - 3177975
09-06 20:10:12.551 10667 11003 W AudioTrack: getTimestamp_l(30): retrograde timestamp position corrected, -110 = 3192072 - 3192182
09-06 20:10:12.869 10667 11003 W AudioTrack: getTimestamp_l(30): retrograde timestamp position corrected, -108 = 3206282 - 3206390
09-06 20:10:13.197 10667 11003 W AudioTrack: getTimestamp_l(30): retrograde timestamp position corrected, -115 = 3220874 - 3220989
09-06 20:10:13.629 10667 11003 W AudioTrack: getTimestamp_l(30): retrograde timestamp position corrected, -107 = 3241222 - 3241329
09-06 20:10:13.957 10667 11003 W AudioTrack: getTimestamp_l(30): retrograde timestamp position corrected, -109 = 3255434 - 3255543
=======================================================

So, it seems like an issue that existed originally.
I think we need to check the root cause of the issue.

Thank you.
Kim

(SW) Sam Yang

2023-09-07 15:17

developer   ~0014104

Hi JunGyu,

For checking the issue, could you please help:
1. What reproducing rates of these three FWs? We will try to reproduce by using the highest FW.
2. What content did you use for testing.
3. Could you please help to dump the btsnoop data from connecting a2dp to the end of playing?

Thanks~
Sam

(ALTech) JunGyu Kim

2023-09-26 14:34

developer   ~0014222

Hi Sam,

1. I think reproducing rates of all three FWs are the same.
    -> When testing as follows, the issue seems to reproduce well.
         1. Reboot STB
         2. Play youtube content
         3. Connect earphone to RCU
         4. The issue is occurred(getTimestamp_l(27): retrograde timestamp position corrected)
2. It seems no relate the content. If the issue is reproduce, it will be the same in all content.
3. I have attached btsnoop log. Please refer it.

Thank you.
Kim
btsnoop_hci.log (1,473,180 bytes)

(ALTech) Younkwang Jung

2023-10-11 17:12

developer   ~0014266

Hi Sam Yang

I have a meeting with SKB tomorrow morning
Please update the progress

Thank you
YK.Jung

(SW) Sam Yang

2023-10-11 17:35

developer   ~0014267

Last edited: 2023-10-11 18:54

Hi Younkwang,

According to the btsnoop_hci.log uploaded by you, the audio stream data inside is already choppy.
So I think that Amlogic audio HAL has some problem( decoding the Youtube audio stream data or encoding to a2dp audio stream ).
Please let Amlogic check this issue.

Thanks~
Sam

(ALTech) Younkwang Jung

2023-10-12 07:56

developer   ~0014269

Hi Sam

> According to the btsnoop_hci.log uploaded by you, the audio stream data inside is already choppy.

How can I know that audio data is already choppy?
Please explain it in the btsnoop_hci.log.

Thank you
YK.Jung

(SW) Sam Yang

2023-10-12 09:31

developer   ~0014272

Hi Younkwang,

You can use btsnoop analysis tool (e.g., Teledyne LeCroy Wireless Protocol Suite 1.4) to export audio data.
The method I use: open "btsnoop_hci.log" => choose A2DP tab => press "V" button in tool bar => press right button to export audio data.
The audio data "audioData.wav" is what I export.

Thanks~
Sam
audioData.wav (8,991,018 bytes)   

(ALTech) JunGyu Kim

2023-12-21 09:22

developer   ~0014792

Hi Sam,

This issue was fixed by Amlogic.
The patch is below.
hardware/amlogic 266e886294 audio_hal: play youtube with a2dp audio breadk [1/1]

Currently this patch was release to test branch and other manufacturer does not apply this patch because their model does not occurring this issue.
Therefore, this patch will not be an official release and only we have to apply the patch.
So, please apply this patch to UI 541 branch. (VCS / Hybrid)

Jira ticket is
https://jira.skbroadband.com/browse/BPM-27223

Thank you.
Kim

(ALTech) Younkwang Jung

2023-12-21 15:13

developer   ~0014800

Hi Sam

I attached is the audio patch file
Please apply it to UI541 (VCS and Hybrid)
Jira id is BPM-27223

Thank you
YK.Jung
image.png (85,444 bytes)   
image.png (85,444 bytes)   
0001-audio_hal-play-youtube-with-a2dp-audio-breadk-1-1.patch (106,231 bytes)   
From b266e886294aeadb947b5f05888029a6b4045461 Mon Sep 17 00:00:00 2001
From: SungHwan Yu <Sh.Yu@amlogic.com>
Date: Wed, 18 Oct 2023 11:03:17 +0900
Subject: [PATCH] audio_hal: play youtube with a2dp audio breadk [1/1]

PD#OTT-50503

Problem:
The Q code is older and needs to be updated.

Solution:
Merge a2dp code from R to Q

Verify:
s905x2

Change-Id: I908b28659ad743ea34343e5a70ba59d7ec20373e
Signed-off-by: SungHwan Yu <Sh.Yu@amlogic.com>
---
 audio/audio_hal/a2dp_hal.cpp           | 850 +++++++++++++++----------
 audio/audio_hal/a2dp_hal.h             |  15 +-
 audio/audio_hal/amlAudioMixer.c        | 478 ++++++--------
 audio/audio_hal/aml_audio_stream.h     |   9 +-
 audio/audio_hal/aml_audio_timer.h      |   8 +
 audio/audio_hal/audio_hw.c             |  80 +--
 audio/audio_hal/audio_hw.h             |   3 +-
 audio/audio_hal/audio_hw_utils.c       |  17 +-
 audio/audio_hal/audio_hw_utils.h       |  57 +-
 audio/audio_hal/audio_port.c           |  38 +-
 audio/audio_hal/audio_port.h           |   8 +-
 audio/audio_hal/sub_mixing_factory.c   |  38 +-
 audio/utils/aml_malloc_debug.c         |  22 +
 audio/utils/include/aml_malloc_debug.h |   1 +
 14 files changed, 907 insertions(+), 717 deletions(-)

diff --git a/audio/audio_hal/a2dp_hal.cpp b/audio/audio_hal/a2dp_hal.cpp
index 48ad717..3ae830c 100644
--- a/audio/audio_hal/a2dp_hal.cpp
+++ b/audio/audio_hal/a2dp_hal.cpp
@@ -15,118 +15,78 @@
  */
 
 #define LOG_TAG  "a2dp_hal"
-
+//#define LOG_NDEBUG 0
 #include <system/audio.h>
+#include <cinttypes>
 #include <cutils/log.h>
 #include <cutils/properties.h>
 #include <android-base/strings.h>
+#include <audio_utils/primitives.h>
+
+#include "BluetoothAudioSession.h"
 
 #include "a2dp_hal.h"
 #include "a2dp_hw.h"
-#include "audio_hw.h"
 
-using ::android::bluetooth::audio::BluetoothAudioPortOut;
+extern "C" {
+#include "aml_malloc_debug.h"
+#include "aml_audio_resampler.h"
+#include "audio_hw_utils.h"
+#include "aml_audio_stream.h"
+#include "aml_audio_timer.h"
+}
 
-#define MAX_RESAMPLE_CHANNEL 8
-struct aml_resample {
-    unsigned int FractionStep;
-    unsigned int SampleFraction;
-    unsigned int input_sr;
-    unsigned int output_sr;
-    unsigned int channels;
-    int16_t lastsample[MAX_RESAMPLE_CHANNEL];
-};
+using ::android::bluetooth::audio::BluetoothAudioPortOut;
+using ::android::bluetooth::audio::BluetoothAudioSession;
+using ::android::bluetooth::audio::BluetoothAudioSessionInstance;
+using ::android::hardware::bluetooth::audio::V2_0::SessionType;
+
+#define A2DP_RING_BUFFER_DELAY_TIME_MS              (64)
+#define A2DP_SEND_DATA_TIMEOUT_RESET_MS             (300)
+#define A2DP_WAIT_STATE_DELAY_TIME_US               (8000)
+#define DEFAULT_A2DP_LATENCY_NS                     (100 * NSEC_PER_MSEC) // Default delay to use when BT device does not report a delay
+#define A2DP_STATIC_DELAY_MS                        (0) // Additional device-specific delay
+#define AUDIO_HAL_FIXED_CFG_CHANNEL                 (AUDIO_CHANNEL_OUT_STEREO)
+#define AUDIO_HAL_FIXED_CFG_FORMAT                  (AUDIO_FORMAT_PCM_16_BIT)
 
 struct aml_a2dp_hal {
     BluetoothAudioPortOut a2dphw;
     audio_config config;
-    struct aml_resample * resample;
-    char* buff;
-    size_t buffsize;
+    struct resample_para *resample;
     int64_t last_write_time;
-    mutable std::mutex mutex_;
+    uint64_t mute_time;
+    char * buff_conv_format;
+    size_t buff_size_conv_format;
+    BluetoothStreamState state;
+    bool is_sending_data;
+    bool exit_out_monitor_thread;
+    pthread_t out_monitor_thread_id;
+    pthread_mutex_t out_monitor_thread_mutex;
+    pthread_cond_t out_monitor_thread_cond;
+    uint32_t     resample_size;
+    char *       resample_buffer;
 };
 
-inline static short clip(int x) {
-    if (x < -32768) {
-        return -32768;
-    } else if (x > 32767) {
-        return 32767;
-    } else {
-        return x;
-    }
-}
-
-int resampler_init(struct aml_resample *resample) {
+static int a2dp_out_standby(struct aml_audio_device *adev);
 
-    ALOGD("%s, Init Resampler: input_sr = %d, output_sr = %d \n",
-        __FUNCTION__,resample->input_sr,resample->output_sr);
-
-    static const double kPhaseMultiplier = 1L << 28;
-    unsigned int i;
-
-    if (resample->channels > MAX_RESAMPLE_CHANNEL) {
-        ALOGE("Error: %s, max support channels: %d\n",
-        __FUNCTION__, MAX_RESAMPLE_CHANNEL);
-        return -1;
-    }
-
-    resample->FractionStep = (unsigned int) (resample->input_sr * kPhaseMultiplier
-                            / resample->output_sr);
-    resample->SampleFraction = 0;
-    for (i = 0; i < resample->channels; i++)
-        resample->lastsample[i] = 0;
-
-    return 0;
+const char* a2dpStatus2String(BluetoothStreamState type)
+{
+    ENUM_TYPE_TO_STR_START("BluetoothStreamState::");
+    ENUM_TYPE_TO_STR(BluetoothStreamState::DISABLED)
+    ENUM_TYPE_TO_STR(BluetoothStreamState::STANDBY)
+    ENUM_TYPE_TO_STR(BluetoothStreamState::STARTING)
+    ENUM_TYPE_TO_STR(BluetoothStreamState::STARTED)
+    ENUM_TYPE_TO_STR(BluetoothStreamState::SUSPENDING)
+    ENUM_TYPE_TO_STR(BluetoothStreamState::UNKNOWN)
+    ENUM_TYPE_TO_STR_END
 }
 
-int resample_process(struct aml_resample *resample, unsigned int in_frame,
-        int16_t* input, int16_t* output) {
-    unsigned int inputIndex = 0;
-    unsigned int outputIndex = 0;
-    unsigned int FractionStep = resample->FractionStep;
-    int16_t last_sample[MAX_RESAMPLE_CHANNEL];
-    unsigned int i;
-    unsigned int channels = resample->channels;
-
-    static const unsigned int kPhaseMask = (1LU << 28) - 1;
-    unsigned int frac = resample->SampleFraction;
-
-    for (i = 0; i < channels; i++)
-        last_sample[i] = resample->lastsample[i];
-
-
-    while (inputIndex == 0) {
-        for (i = 0; i < channels; i++) {
-            *output++ = clip((int) last_sample[i] +
-                ((((int) input[i] - (int) last_sample[i]) * ((int) frac >> 13)) >> 15));
-        }
-
-        frac += FractionStep;
-        inputIndex += (frac >> 28);
-        frac = (frac & kPhaseMask);
-        outputIndex++;
-    }
-
-    while (inputIndex < in_frame) {
-        for (i = 0; i < channels; i++) {
-            *output++ = clip((int) input[channels * (inputIndex - 1) + i] +
-                ((((int) input[channels * inputIndex + i]
-                - (int) input[channels * (inputIndex - 1) + i]) * ((int) frac >> 13)) >> 15));
-        }
-
-        frac += FractionStep;
-        inputIndex += (frac >> 28);
-        frac = (frac & kPhaseMask);
-        outputIndex++;
-    }
-
-    resample->SampleFraction = frac;
-
-    for (i = 0; i < channels; i++)
-        resample->lastsample[i] = input[channels * (in_frame - 1) + i];
-
-    return outputIndex;
+struct timespec aml_audio_ns_to_time(uint64_t ns)
+{
+    struct timespec time;
+    time.tv_sec = ns / 1000000000;
+    time.tv_nsec = ns - ((uint64_t)time.tv_sec * 1000000000);
+    return time;
 }
 
 std::unordered_map<std::string, std::string> ParseAudioParams(const std::string& params) {
@@ -138,7 +98,7 @@ std::unordered_map<std::string, std::string> ParseAudioParams(const std::string&
         }
         std::vector<std::string> kv = android::base::Split(segment, "=");
         if (kv[0].empty()) {
-            //ALOGD("%s: Invalid audio parameter: ", __func__, segment.char());
+            //AM_LOGD("Invalid audio parameter: ", segment.char());
             continue;
         }
         params_map[kv[0]] = (kv.size() > 1 ? kv[1] : "");
@@ -146,357 +106,532 @@ std::unordered_map<std::string, std::string> ParseAudioParams(const std::string&
     return params_map;
 }
 
-int a2dp_out_open(struct audio_hw_device* dev) {
-    struct aml_audio_device *adev = (struct aml_audio_device *)dev;
+static bool a2dp_wait_status(struct aml_a2dp_hal *hal) {
+    hal->state = hal->a2dphw.GetState();
+    int retry = 0;
+    while (retry < 100) {
+        if ((hal->state != BluetoothStreamState::STARTING) && (hal->state != BluetoothStreamState::SUSPENDING)) {
+            if (retry > 0) {
+                AM_LOGD("a2dp wait for %d ms, state:%s",
+                    retry * A2DP_WAIT_STATE_DELAY_TIME_US / 1000, a2dpStatus2String(hal->state));
+            }
+            return true;
+        }
+        usleep(A2DP_WAIT_STATE_DELAY_TIME_US);
+        retry++;
+        hal->state = hal->a2dphw.GetState();
+    }
+    AM_LOGW("a2dp wait timeout for %d ms, state:%s",
+        retry * A2DP_WAIT_STATE_DELAY_TIME_US / 1000, a2dpStatus2String(hal->state));
+    return false;
+}
+
+static void dump_a2dp_output_data(aml_a2dp_hal *hal, const void *buffer, uint32_t size) {
+    if (getprop_bool("vendor.media.audiohal.a2dpdump")) {
+        char acFilePathStr[ENUM_TYPE_STR_MAX_LEN];
+        size_t out_per_sample_byte = audio_bytes_per_sample(hal->config.format);
+        size_t out_channel_byte = audio_channel_count_from_out_mask(hal->config.channel_mask);
+        sprintf(acFilePathStr, "/data/audio/a2dp_%0.1fK_%zuC_%zuB.pcm", hal->config.sample_rate/1000.0, out_channel_byte, out_per_sample_byte);
+        aml_audio_dump_audio_bitstreams(acFilePathStr, buffer, size);
+    }
+}
+
+static void a2dp_notify_monitor(aml_a2dp_hal *hal, bool is_sending = false) {
+    pthread_mutex_lock(&hal->out_monitor_thread_mutex);
+    hal->is_sending_data = is_sending;
+    pthread_cond_signal(&hal->out_monitor_thread_cond);
+    pthread_mutex_unlock(&hal->out_monitor_thread_mutex);
+}
+
+static void *a2dp_out_monitor_thread(void *arg) {
+    struct aml_audio_device *adev = (struct aml_audio_device *)arg;
+    aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
+    struct timespec next_time;
+    uint32_t timeout_ms = 0;
+    bool is_standby = true;
+    int ret = 0;
+    AM_LOGI("Start monitoring the write rate+++");
+    uint64_t time_ns;
+    while (hal->exit_out_monitor_thread == false) {
+        pthread_mutex_lock(&hal->out_monitor_thread_mutex);
+        if (is_standby) {
+            ret = pthread_cond_wait(&hal->out_monitor_thread_cond, &hal->out_monitor_thread_mutex);
+        } else {
+            timeout_ms = A2DP_RING_BUFFER_DELAY_TIME_MS; // 64 ms
+            if (hal->is_sending_data) {
+                timeout_ms = A2DP_SEND_DATA_TIMEOUT_RESET_MS; // 300ms
+            }
+            /* Here is an empirical value 64ms, when each write interval is greater than this value, we think standby BT,
+             * needed to reduce power consumption.
+             */
+            time_ns = aml_audio_get_systime_ns();
+            next_time = aml_audio_ns_to_time(time_ns + timeout_ms * NSEC_PER_MSEC);
+            ret = pthread_cond_timedwait(&hal->out_monitor_thread_cond, &hal->out_monitor_thread_mutex, &next_time);
+        }
+
+        if (timeout_ms == A2DP_SEND_DATA_TIMEOUT_RESET_MS) {
+            AM_LOGV("send bt elapsed time: %" PRIu64 " ms", (aml_audio_get_systime_ns() - time_ns) / NSEC_PER_MSEC);
+        }
+        pthread_mutex_unlock(&hal->out_monitor_thread_mutex);
+        if (ret == ETIMEDOUT && hal->exit_out_monitor_thread == false) {
+            if (timeout_ms == A2DP_SEND_DATA_TIMEOUT_RESET_MS) {
+                AM_LOGW("send BT stack timeout %dms, need standby, cur_state:%s", timeout_ms, a2dpStatus2String(hal->state));
+            } else {
+                AM_LOGI("audio write timeout %dms, need standby, cur_state:%s", timeout_ms, a2dpStatus2String(hal->state));
+            }
+            a2dp_out_standby(adev);
+            is_standby = true;
+        } else {
+            is_standby = false;
+        }
+    }
+    AM_LOGI("Exit the monitor---");
+    return NULL;
+}
+
+int a2dp_out_open(struct aml_audio_device *adev) {
     struct aml_a2dp_hal * hal = NULL;
+    struct timespec ts = {.tv_sec = 0, .tv_nsec = 0};
+    pthread_mutex_lock(&adev->a2dp_lock);
 
     if (adev->a2dp_hal != NULL) {
-        ALOGE("BluetoothAudioPortOut already exist");
+        AM_LOGW("already open");
+        pthread_mutex_unlock(&adev->a2dp_lock);
         return 0;
     }
-    ALOGD("%s: open", __func__);
-
-    hal = new aml_a2dp_hal;
+    hal = (struct aml_a2dp_hal *)aml_audio_calloc(1, sizeof(struct aml_a2dp_hal));
     if (hal == NULL) {
-        ALOGE("new BluetoothAudioPortOut fail");
+        AM_LOGE("new BluetoothAudioPortOut fail");
+        pthread_mutex_unlock(&adev->a2dp_lock);
         return -1;
     }
     hal->resample = NULL;
-    hal->buff = NULL;
-    hal->buffsize = 0;
+    hal->buff_conv_format = NULL;
+    hal->buff_size_conv_format = 0;
+    hal->state = BluetoothStreamState::UNKNOWN;
     if (!hal->a2dphw.SetUp(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP)) {
-        ALOGE("BluetoothAudioPortOut setup fail");
+        AM_LOGE("BluetoothAudioPortOut setup fail");
+        pthread_mutex_unlock(&adev->a2dp_lock);
+        delete hal;
         return -1;
     }
     if (!hal->a2dphw.LoadAudioConfig(&hal->config)) {
-        ALOGE("LoadAudioConfig fail");
+        AM_LOGE("LoadAudioConfig fail");
     }
     if (hal->config.channel_mask == AUDIO_CHANNEL_OUT_MONO)
         hal->a2dphw.ForcePcmStereoToMono(true);
-
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    hal->mute_time = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
+    hal->mute_time += 1000000LL; // mute for 1s
     adev->a2dp_hal = (void*)hal;
-    ALOGD("LoadAudioConfig: rate=%d, format=%x, ch=%d",
-        hal->config.sample_rate, hal->config.format, hal->config.channel_mask);
+    pthread_mutex_unlock(&adev->a2dp_lock);
+
+    pthread_condattr_t condattr;
+    pthread_mutex_init(&hal->out_monitor_thread_mutex, NULL);
+    pthread_condattr_init(&condattr);
+    pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
+    pthread_cond_init(&hal->out_monitor_thread_cond, &condattr);
+    pthread_condattr_destroy(&condattr);
+    hal->exit_out_monitor_thread = false;
+    hal->is_sending_data = false;
+    int pthread_ret = pthread_create(&hal->out_monitor_thread_id, NULL, &a2dp_out_monitor_thread, adev);
+    if (pthread_ret != 0) {
+        AM_LOGE("pthread_create fail");
+        return -1;
+    }
+    AM_LOGI("Rx param rate:%d, bytes_per_sample:%zu, ch:%d", hal->config.sample_rate,
+        audio_bytes_per_sample(hal->config.format), audio_channel_count_from_out_mask(hal->config.channel_mask));
     return 0;
 }
-int a2dp_out_close(struct audio_hw_device* dev) {
-    struct aml_audio_device *adev = (struct aml_audio_device *)dev;
-    struct aml_a2dp_hal * hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
 
+int a2dp_out_close(struct aml_audio_device *adev) {
+    pthread_mutex_lock(&adev->a2dp_lock);
+    struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
     if (hal == NULL) {
-        ALOGE("a2dp hw already release");
+        AM_LOGW("a2dp hw is already closed.");
+        pthread_mutex_unlock(&adev->a2dp_lock);
         return -1;
     }
+
+    hal->exit_out_monitor_thread = true;
+    a2dp_notify_monitor(hal);
+    pthread_join(hal->out_monitor_thread_id, NULL);
+    pthread_cond_destroy(&hal->out_monitor_thread_cond);
+    pthread_mutex_destroy(&hal->out_monitor_thread_mutex);
     adev->a2dp_hal = NULL;
-    hal->mutex_.lock();
-    ALOGD("%s: close", __func__);
+    AM_LOGI("");
+    /*coverity[sleep]*/
+    a2dp_wait_status(hal);
     hal->a2dphw.Stop();
     hal->a2dphw.TearDown();
-    if (hal->resample)
-        delete hal->resample;
-    if (hal->buff)
-        delete hal->buff;
-    hal->mutex_.unlock();
+    if (hal->resample) {
+        aml_audio_free(hal->resample);
+        hal->resample = NULL;
+    }
+    if (hal->resample_buffer) {
+        aml_audio_free(hal->resample_buffer);
+        hal->resample_buffer = NULL;
+        hal->resample_size = 0;
+    }
+    if (hal->buff_conv_format)
+        aml_audio_free(hal->buff_conv_format);
+    pthread_mutex_unlock(&adev->a2dp_lock);
     delete hal;
-    adev->a2dp_active = 0;
     return 0;
 }
 
-int a2dp_out_resume(struct audio_stream_out* stream) {
-    struct aml_stream_out* out = (struct aml_stream_out*)stream;
-    struct aml_audio_device *adev = out->dev;
-    struct aml_a2dp_hal * hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
-    BluetoothStreamState state;
-
-    if (hal == NULL) {
-        ALOGE("%s: a2dp hw is release", __func__);
-        return -1;
-    }
-
-    std::unique_lock<std::mutex> lock(hal->mutex_);
-    state = hal->a2dphw.GetState();
-    ALOGD("%s: state=%d", __func__, (uint8_t)state);
-    if (state == BluetoothStreamState::STANDBY) {
+static int a2dp_out_resume_l(aml_audio_device *adev) {
+    struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
+    a2dp_wait_status(hal);
+    if (hal->state == BluetoothStreamState::STARTED) {
+        AM_LOGI("A2dp already resumed. status:%s", a2dpStatus2String(hal->state));
+        return 0;
+    } else if (hal->state == BluetoothStreamState::STANDBY) {
         if (hal->a2dphw.Start()) {
-            if ((out->flags & AUDIO_OUTPUT_FLAG_PRIMARY) == 0)
-                adev->a2dp_active = 1;
+            BluetoothStreamState cur_status = hal->a2dphw.GetState();
+            AM_LOGI("status: %s -> %s Resume in progress...", a2dpStatus2String(hal->state), a2dpStatus2String(cur_status));
+            hal->state = cur_status;
             return 0;
         }
     }
+    AM_LOGW("error state:%s", a2dpStatus2String(hal->state));
     return -1;
 }
 
-int a2dp_out_standby(struct audio_stream* stream) {
-    struct aml_stream_out* out = (struct aml_stream_out*)stream;
-    struct aml_audio_device *adev = out->dev;
-    struct aml_a2dp_hal * hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
-    BluetoothStreamState state;
-
+static int a2dp_out_resume(struct aml_audio_device *adev) {
+    pthread_mutex_lock(&adev->a2dp_lock);
+    struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
     if (hal == NULL) {
-        ALOGE("%s: a2dp hw is release", __func__);
+        AM_LOGW("a2dp has been released.");
+        pthread_mutex_unlock(&adev->a2dp_lock);
         return -1;
     }
+    /*coverity[sleep]*/
+    int32_t ret = a2dp_out_resume_l(adev);
+    pthread_mutex_unlock(&adev->a2dp_lock);
+    return ret;
+}
 
-    if (adev->hal_audio_open_times > 0) {
-        ALOGE("%s: hal_audio_open_times=%d, not close",
-            __func__, adev->hal_audio_open_times);
+static int a2dp_out_standby_l(struct aml_audio_device *adev) {
+    struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
+    a2dp_wait_status(hal);
+    if (hal->state == BluetoothStreamState::STANDBY) {
+        AM_LOGI("A2dp already standby. status:%s", a2dpStatus2String(hal->state));
         return 0;
-    }
-
-    std::unique_lock<std::mutex> lock(hal->mutex_);
-    state = hal->a2dphw.GetState();
-    ALOGD("%s: state=%d", __func__, (uint8_t)state);
-    if (state == BluetoothStreamState::STARTED) {
+    } else if (hal->state == BluetoothStreamState::STARTED) {
         if (hal->a2dphw.Suspend()) {
-            if ((out->flags & AUDIO_OUTPUT_FLAG_PRIMARY) == 0)
-                adev->a2dp_active = 0;
+            BluetoothStreamState cur_status = hal->a2dphw.GetState();
+            AM_LOGI("status: %s -> %s Standby in progress...", a2dpStatus2String(hal->state), a2dpStatus2String(cur_status));
+            hal->state = cur_status;
             return 0;
         }
     }
+    AM_LOGW("error state:%s", a2dpStatus2String(hal->state));
     return -1;
 }
 
-
-
-ssize_t a2dp_out_write_new(void *adev_ptr, void *hal_ptr, int is_tv_platform, int hal_rate, unsigned int flags, const void* buffer, size_t bytes) 
-{
-    struct aml_audio_device *adev = (struct aml_audio_device *)adev_ptr;
-    struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)hal_ptr;
-    BluetoothStreamState state;
-    size_t totalWritten = 0;
-    int frame_size = 4; //2ch 16bits
-    size_t frames = bytes / frame_size;
-
+static int a2dp_out_standby(struct aml_audio_device *adev) {
+    pthread_mutex_lock(&adev->a2dp_lock);
+    struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
     if (hal == NULL) {
-        ALOGE("%s: a2dp hw is release", __func__);
+        AM_LOGW("a2dp has been released.");
+        pthread_mutex_unlock(&adev->a2dp_lock);
         return -1;
     }
-    std::unique_lock<std::mutex> lock(hal->mutex_);
-    state = hal->a2dphw.GetState();
-    lock.unlock();
-
-    if (state != BluetoothStreamState::STARTED) 
-    {
-        bool wait = true;
-        {
-            lock.lock();
-            state = hal->a2dphw.GetState();
-            ALOGD("%s: state=%d", __func__, (uint8_t)state);
-            if (state == BluetoothStreamState::STANDBY) 
-            {
-                if (hal->a2dphw.Start()) 
-                {
-                    if ((flags & AUDIO_OUTPUT_FLAG_PRIMARY) == 0) adev->a2dp_active = 1;
-                    wait = false;
-                }
+    if (adev->hal_audio_open_times > 0) {
+	ALOGE("%s: hal_audio_open_times=%d, not close",
+		__func__, adev->hal_audio_open_times);
+        pthread_mutex_unlock(&adev->a2dp_lock);
+	return 0;
+    }
+    /*coverity[sleep]*/
+    int32_t ret = a2dp_out_standby_l(adev);
+    pthread_mutex_unlock(&adev->a2dp_lock);
+    return ret;
+}
+
+static bool a2dp_state_process(struct aml_audio_device *adev, audio_config_base_t *config, size_t cur_frames) {
+    aml_a2dp_hal            *hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
+    BluetoothStreamState    cur_state = hal->a2dphw.GetState();
+    const int64_t           cur_write_time_us = aml_audio_get_systime();
+    bool                    prepared = false;
+
+    const int64_t write_delta_time_us = cur_write_time_us - hal->last_write_time;
+    int64_t data_delta_time_us = (int64_t)(cur_frames * USEC_PER_SEC / config->sample_rate) - write_delta_time_us;
+    hal->last_write_time = cur_write_time_us;
+    if (hal->state != cur_state) {
+        AM_LOGI("a2dp state changed: %s -> %s",  a2dpStatus2String(hal->state), a2dpStatus2String(cur_state));
+        hal->state = cur_state;
+    }
+    if (adev->debug_flag) {
+        AM_LOGD("cur_state:%s, frames:%zu, gap:%" PRId64 " ms", a2dpStatus2String(cur_state), cur_frames, write_delta_time_us / 1000);
+    }
+
+    if (cur_state == BluetoothStreamState::STARTING) {
+        if (data_delta_time_us > 0) {
+            if (adev->debug_flag) {
+                AM_LOGD("write too fast, need sleep:%" PRId64 " ms", data_delta_time_us / 1000);
             }
-            lock.unlock();
+            usleep(data_delta_time_us);
         }
-
-        if (wait) usleep(10 * 1000);
-        return totalWritten;
+    } else if (cur_state == BluetoothStreamState::STARTED) {
+         if (adev->audio_patch && adev->tv_mute) {
+            /* tv_mute for atv switch channel */
+            AM_LOGI("tv_mute:%d, start standby", adev->tv_mute);
+            a2dp_out_standby_l(adev);
+        } else {
+            prepared = true;
+        }
+    } else if (cur_state == BluetoothStreamState::DISABLED) {
+        // TODO: A2DP is disconnected. do nothing.
+    } else {
+        struct aml_audio_patch *patch = adev->audio_patch;
+        if (!(adev->tv_mute && patch)) {
+            a2dp_out_resume_l(adev);
+        }
+        // a2dp_out_resume maybe cause over 100ms, so set last_write_time after resume,
+        // otherwise, the gap would always over 64ms, and always standby in dtv
+        hal->last_write_time = aml_audio_get_systime();
     }
+    return prepared;
+}
 
-    if (is_tv_platform == 1) {
-        int16_t *tmp_buffer = (int16_t *)buffer;
+static ssize_t a2dp_in_data_process(aml_a2dp_hal *hal, audio_config_base_t *config, const void *buffer, size_t bytes) {
+    size_t frames = 0;
+    int realloc_ret = 0;
+    if (config->channel_mask == AUDIO_CHANNEL_OUT_7POINT1 && config->format == AUDIO_FORMAT_PCM_32_BIT) {
+        frames = bytes / (4 * 8);
+        realloc_ret = aml_audio_check_and_realloc((void **)&hal->buff_conv_format, &hal->buff_size_conv_format, frames * 4);
+        if (realloc_ret != 0) {
+            AM_LOGE("aml_audio_check_and_realloc fail");
+            return -1;
+        }
+        int16_t *tmp_buffer = (int16_t *)hal->buff_conv_format;
         int32_t *tmp_buffer_8ch = (int32_t *)buffer;
-        frames = bytes/32; // 8ch 32bit
-        for (int i=0; i<(int)frames; i++) {
-            tmp_buffer[2*i] = (tmp_buffer_8ch[8*i]>>16);
-            tmp_buffer[2*i+1] = (tmp_buffer_8ch[8*i+1]>>16);
+        for (int i=0; i<frames; i++) {
+            tmp_buffer[2 * i]       = (tmp_buffer_8ch[8 *  i] >> 16);
+            tmp_buffer[2 * i + 1]   = (tmp_buffer_8ch[8 * i + 1] >> 16);
+        }
+    } else if (config->channel_mask == AUDIO_CHANNEL_OUT_STEREO && config->format == AUDIO_FORMAT_PCM_16_BIT) {
+        frames = bytes / (2 * 2);
+        realloc_ret = aml_audio_check_and_realloc((void **)&hal->buff_conv_format, &hal->buff_size_conv_format, bytes);
+        if (realloc_ret != 0) {
+            AM_LOGE("aml_audio_check_and_realloc fail");
+            return -1;
         }
+        memcpy(hal->buff_conv_format, buffer, bytes);
+    } else {
+        AM_LOGW("not support param, channel_cnt:%d, format:%#x",
+            audio_channel_count_from_out_mask(config->channel_mask), config->format);
+        return -1;
     }
 
-    struct timespec ts = {.tv_sec = 0, .tv_nsec = 0};
-    clock_gettime(CLOCK_MONOTONIC, &ts);
+    const int64_t cur_write_time_us = aml_audio_get_systime();
+    if (hal->mute_time > 0) {
+        if (hal->mute_time > cur_write_time_us) {
+            memset((void*)buffer, 0, bytes);
+        } else {
+            hal->mute_time = 0;
+        }
+    }
+    return frames;
+}
 
-    if (hal_rate != hal->config.sample_rate) {
-        int out_frames = 0;
-        int out_size = frames*hal->config.sample_rate*frame_size/hal_rate+32;
-        if (hal->resample == NULL) {
-            hal->resample = new aml_resample;
+static ssize_t a2dp_data_resample_process(aml_a2dp_hal *hal, audio_config_base_t *input_cfg,
+    const void *buffer, size_t in_frames, const void **output_buffer) {
+    int out_frames = in_frames;
+    *output_buffer = buffer;
+    if (input_cfg->sample_rate != hal->config.sample_rate) {
+        size_t in_frame_size = audio_channel_count_from_out_mask(AUDIO_HAL_FIXED_CFG_CHANNEL) *
+            audio_bytes_per_sample(AUDIO_HAL_FIXED_CFG_FORMAT);
+        /* The resampled frames may be large than the theoretical value.
+         * So, there is an extra 32 bytes allocated to prevent overflows.
+         */
+        int resample_out_buffer_size = in_frames * hal->config.sample_rate * in_frame_size / input_cfg->sample_rate + 32;
+        if (hal->resample == NULL || hal->resample->input_sr != input_cfg->sample_rate) {
+            if (hal->resample) {
+                delete hal->resample;
+                hal->resample = NULL;
+            }
+            hal->resample = (struct resample_para *)aml_audio_calloc(1, sizeof(struct resample_para));
             if (hal->resample == NULL) {
-                ALOGD("%s: new resample_para error", __func__);
-                return bytes;
+                AM_LOGE("new aml_resample error");
+                return 0;
             }
-            hal->resample->input_sr = hal_rate;
+            hal->resample->input_sr = input_cfg->sample_rate;
             hal->resample->output_sr = hal->config.sample_rate;
-            hal->resample->channels = 2;
+            hal->resample->channels = audio_channel_count_from_out_mask(AUDIO_HAL_FIXED_CFG_CHANNEL);
             resampler_init(hal->resample);
         }
-        if (hal->buffsize < out_size) {
-            if (hal->buff)
-                delete[] hal->buff;
-            hal->buff = new char[out_size];
-            if (hal->buff == NULL) {
-                ALOGD("%s: new buff error", __func__);
-                return bytes;
-            }
-            hal->buffsize = out_size;
+        int out_size = in_frames * in_frame_size * hal->resample->output_sr / hal->resample->input_sr + 32;
+        int realloc_ret = aml_audio_check_and_realloc((void **)&hal->resample_buffer, &hal->resample_size, out_size);
+        if (realloc_ret != 0) {
+            AM_LOGE("aml_audio_check_and_realloc fail");
+            return -1;
         }
-        out_frames = resample_process(hal->resample, frames, (int16_t*) buffer, (int16_t*) hal->buff);
+        out_frames = resample_process(hal->resample, in_frames, (int16_t*)buffer, (int16_t*)hal->resample_buffer);
         if (out_frames == 0) {
-            return bytes;
+            AM_LOGW("resample_process return 0.");
+            return 0;
         }
-        out_size = out_frames * frame_size;
-        frames = out_frames;
-        if (property_get_int32("vendor.media.audiohal.a2dp", 0) > 0) {
-            FILE *fp = fopen("/data/audio/a2dp.pcm", "a+");
-            if (fp) {
-                int flen = fwrite((char *)hal->buff, 1, out_size, fp);
-                fclose(fp);
-            }
+        *output_buffer = hal->resample_buffer;
+    }
+    return out_frames;
+}
+
+static ssize_t a2dp_out_data_process(aml_a2dp_hal *hal, audio_config_base_t *config __unused,
+    const void *buffer, size_t in_frames, const void **output_buffer) {
+    size_t in_frame_size = audio_channel_count_from_out_mask(AUDIO_HAL_FIXED_CFG_CHANNEL) *
+        audio_bytes_per_sample(AUDIO_HAL_FIXED_CFG_FORMAT);
+    ssize_t out_size = in_frames * in_frame_size;
+    if (hal->config.channel_mask == AUDIO_CHANNEL_OUT_MONO) {
+        int16_t *tmp_buffer = (int16_t *)buffer;
+        for (int i=0; i<in_frames; i++) {
+            tmp_buffer[i] = tmp_buffer[2 * i];
         }
-        lock.lock();
-        totalWritten = hal->a2dphw.WriteData(hal->buff, out_size);
-        lock.unlock();
+        out_size = in_frames * 1 * audio_bytes_per_sample(AUDIO_HAL_FIXED_CFG_FORMAT);
+    } else if (hal->config.channel_mask == AUDIO_CHANNEL_OUT_STEREO) {
+        /* 2channel do nothing*/
     } else {
-        lock.lock();
-        totalWritten = hal->a2dphw.WriteData(buffer, bytes);
-        lock.unlock();
-        if (property_get_int32("vendor.media.audiohal.a2dp", 0) > 0) {
-            FILE *fp = fopen("/data/audio/a2dp.pcm", "a+");
-            if (fp) {
-                int flen = fwrite((char *)buffer, 1, bytes, fp);
-                fclose(fp);
-            }
-        }
+        AM_LOGW("not support a2dp output channel_cnt:%#x",
+            audio_channel_count_from_out_mask(AUDIO_HAL_FIXED_CFG_CHANNEL));
+        return 0;
     }
-    if (totalWritten) {
-        hal->last_write_time = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
-    } else {
-        const int64_t now = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
-        const int64_t gap = now - hal->last_write_time;
-        int64_t sleep_time = frames * 1000000LL / hal->config.sample_rate - gap;
-        hal->last_write_time = now;
-        if (sleep_time > 0) {
-            hal->last_write_time += sleep_time;
-            usleep(sleep_time);
+
+    size_t out_per_sample_byte = audio_bytes_per_sample(hal->config.format);
+    size_t out_channel_byte = audio_channel_count_from_out_mask(hal->config.channel_mask);
+    out_size = out_per_sample_byte * out_channel_byte * in_frames;
+    if (hal->config.format != AUDIO_FORMAT_PCM_16_BIT) {
+        int realloc_ret = aml_audio_check_and_realloc((void **)&hal->buff_conv_format, &hal->buff_size_conv_format, out_size);
+        if (realloc_ret != 0) {
+            AM_LOGE("aml_audio_check_and_realloc fail");
+            return 0;
         }
+        R_CHECK_RET(0, "realloc buff_conv_format size:%zu fail", out_size);
+        if (hal->config.format == AUDIO_FORMAT_PCM_32_BIT) {
+            memcpy_to_i32_from_i16((int32_t *)hal->buff_conv_format, (int16_t *)buffer, in_frames * out_channel_byte);
+        } else if (hal->config.format == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
+            memcpy_to_p24_from_i16((uint8_t *)hal->buff_conv_format, (int16_t *)buffer, in_frames * out_channel_byte);
+        } else {
+            AM_LOGW("not support a2dp output format:%#x", hal->config.format);
+            return 0;
+        }
+        *output_buffer = hal->buff_conv_format;
     }
-    return totalWritten;
+    return out_size;
 }
 
+static ssize_t a2dp_out_write_l(struct aml_audio_device *adev, audio_config_base_t *config, const void* buffer, size_t bytes) {
+    aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
+    int wr_size = 0;
+    const void *wr_buff = NULL;
+    ssize_t cur_frames = 0;
+    ssize_t resample_frames = 0;
+    uint32_t bytes_written = 0;
+    uint64_t pre_time_us = 0;
+    size_t sent = 0;
+
+    if (adev->a2dp_hal == NULL) {
+        if (adev->debug_flag) {
+            AM_LOGW("a2dp_hal is null pointer");
+         }
+        return bytes;
+    }
+
+    cur_frames = a2dp_in_data_process(hal, config, buffer, bytes);
+    if (cur_frames < 0) {
+        return bytes;
+    }
 
+    if (!a2dp_state_process(adev, config, cur_frames)) {
+        a2dp_notify_monitor(hal);
+        return bytes;
+    }
 
-ssize_t a2dp_out_write(struct audio_stream_out* stream, const void* buffer, size_t bytes) {
-    struct aml_stream_out* out = (struct aml_stream_out*)stream;
-    struct aml_audio_device *adev = out->dev;
-    struct aml_a2dp_hal * hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
-    BluetoothStreamState state;
-    size_t totalWritten = 0;
-    int frame_size = 4; //2ch 16bits
-    size_t frames = bytes / frame_size;
+    resample_frames = a2dp_data_resample_process(hal, config, hal->buff_conv_format, cur_frames, &wr_buff);
+    if (resample_frames < 0) {
+        return bytes;
+    }
 
-    if (hal == NULL) {
-        ALOGE("%s: a2dp hw is release", __func__);
-        return -1;
+    wr_size = a2dp_out_data_process(hal, config, wr_buff, resample_frames, &wr_buff);
+    if (wr_size == 0) {
+        return bytes;
     }
-    std::unique_lock<std::mutex> lock(hal->mutex_);
-    state = hal->a2dphw.GetState();
-    if (adev->debug_flag)
-        ALOGD("%s:%p bytes=%d, state=%d, format=0x%x, hwsync=%d, continuous=%d,out->hal_rate=%d,hal->config.sample_rate=%d",
-                __func__, out, bytes, (uint8_t)state, out->hal_internal_format,
-                out->hw_sync_mode, adev->continuous_audio_mode, out->hal_rate, hal->config.sample_rate);
-    if (state != BluetoothStreamState::STARTED) {
-        lock.unlock();
-        if (a2dp_out_resume(stream)) {
-            usleep(10 * 1000);
-        }
-        return totalWritten;
+
+    if (adev->patch_src == SRC_DTV && adev->parental_control_av_mute) {
+        memset((void*)wr_buff, 0, wr_size);
     }
-    if (out->is_tv_platform == 1) {
-        int16_t *tmp_buffer = (int16_t *)buffer;
-        int32_t *tmp_buffer_8ch = (int32_t *)buffer;
-        frames = bytes/32; // 8ch 32bit
-        for (int i=0; i<(int)frames; i++) {
-            tmp_buffer[2*i] = (tmp_buffer_8ch[8*i]>>16);
-            tmp_buffer[2*i+1] = (tmp_buffer_8ch[8*i+1]>>16);
+    dump_a2dp_output_data(hal, wr_buff, wr_size);
+    pre_time_us = aml_audio_get_systime();
+    while (bytes_written < wr_size) {
+        a2dp_notify_monitor(hal, true);
+        sent = hal->a2dphw.WriteData((char *)wr_buff + bytes_written, wr_size - bytes_written);
+        a2dp_notify_monitor(hal);
+        bytes_written += sent;
+        /* The cache of BT stack is about 40ms data, and exit from writing data
+         * after timeout of 64ms here. */
+        if (bytes_written < wr_size && (aml_audio_get_systime() - pre_time_us) > 64 * USEC_PER_MSEC) {
+            AM_LOGW("WriteData timeout 100 ms, quit now.");
+            break;
         }
     }
-    struct timespec ts = {.tv_sec = 0, .tv_nsec = 0};
-    clock_gettime(CLOCK_MONOTONIC, &ts);
+    return bytes;
+}
 
-    if (out->hal_rate != hal->config.sample_rate) {
-        int out_frames = 0;
-        int out_size = frames*hal->config.sample_rate*frame_size/out->hal_rate+32;
-        if (hal->resample == NULL) {
-            hal->resample = new aml_resample;
-            if (hal->resample == NULL) {
-                ALOGD("%s: new resample_para error", __func__);
-                return bytes;
-            }
-            hal->resample->input_sr = out->hal_rate;
-            hal->resample->output_sr = hal->config.sample_rate;
-            hal->resample->channels = 2;
-            resampler_init(hal->resample);
-        }
-        if (hal->buffsize < out_size) {
-            if (hal->buff)
-                delete[] hal->buff;
-            hal->buff = new char[out_size];
-            if (hal->buff == NULL) {
-                ALOGD("%s: new buff error", __func__);
-                return bytes;
-            }
-            hal->buffsize = out_size;
-        }
-        out_frames = resample_process(hal->resample, frames, (int16_t*) buffer, (int16_t*) hal->buff);
-        if (out_frames == 0) {
-            return bytes;
-        }
-        out_size = out_frames * frame_size;
-        frames = out_frames;
-
-        if (property_get_int32("vendor.media.audiohal.a2dp", 0) > 0) {
-            FILE *fp = fopen("/data/audio/a2dp.pcm", "a+");
-            if (fp) {
-                int flen = fwrite((char *)hal->buff, 1, out_size, fp);
-                fclose(fp);
-            }
-        }
+ssize_t a2dp_out_write(struct aml_audio_device *adev, audio_config_base_t *config, const void* buffer, size_t bytes) {
+    size_t in_frame_size = audio_channel_count_from_out_mask(config->channel_mask) * audio_bytes_per_sample(config->format);
+    uint32_t one_ms_data = in_frame_size * config->sample_rate / 1000;
+    uint32_t date_len_ms = bytes / one_ms_data;
+    const uint32_t period_time_ms = 32;
+    const uint32_t period_time_size = one_ms_data * period_time_ms;
 
-        totalWritten = hal->a2dphw.WriteData(hal->buff, out_size);
-    } else {
-        totalWritten = hal->a2dphw.WriteData(buffer, bytes);
-        if (property_get_int32("vendor.media.audiohal.a2dp", 0) > 0) {
-            FILE *fp = fopen("/data/audio/a2dp.pcm", "a+");
-            if (fp) {
-                int flen = fwrite((char *)buffer, 1, bytes, fp);
-                fclose(fp);
-            }
-        }
+    if (bytes == 0) {
+        AM_LOGW("bytes is 0");
+        return -1;
     }
-    if (totalWritten) {
-        hal->last_write_time = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
-    } else {
-        const int64_t now = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
-        const int64_t gap = now - hal->last_write_time;
-        int64_t sleep_time = frames * 1000000LL / hal->config.sample_rate - gap;
-        hal->last_write_time = now;
-        if (sleep_time > 0) {
-            hal->last_write_time += sleep_time;
-            lock.unlock();
-            usleep(sleep_time);
+    R_CHECK_POINTER_LEGAL(-1, config, "");
+    R_CHECK_POINTER_LEGAL(-1, buffer, "");
+
+    uint32_t written_size = 0;
+    pthread_mutex_lock(&adev->a2dp_lock);
+    while (bytes > written_size) {
+        uint32_t remain_size = bytes - written_size;
+        size_t sent = remain_size;
+        if (remain_size > period_time_ms * one_ms_data) {
+            sent = period_time_size;
         }
+        /*coverity[sleep]*/
+        a2dp_out_write_l(adev, config, (char *)buffer + written_size, sent);
+        AM_LOGV("written_size:%d, remain_size:%d, sent:%zu", written_size, remain_size, sent);
+        written_size += sent;
     }
-    return totalWritten;
+    pthread_mutex_unlock(&adev->a2dp_lock);
+    return written_size;
 }
 
-uint32_t a2dp_out_get_latency(const struct audio_stream_out* stream) {
-    (void *)stream;
-    return 200;
+uint32_t a2dp_out_get_latency(struct aml_audio_device *adev __unused) {
+    uint64_t remote_delay_report_ns = 0;
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH);
+    bool success = session_ptr->GetPresentationPosition(&remote_delay_report_ns, nullptr, nullptr);
+    if (!success || remote_delay_report_ns == 0) {
+        remote_delay_report_ns = DEFAULT_A2DP_LATENCY_NS;
+    }
+    return static_cast<uint32_t>(remote_delay_report_ns / NSEC_PER_MSEC + A2DP_STATIC_DELAY_MS);
 }
 
-int a2dp_out_set_parameters (struct audio_stream *stream, const char *kvpairs) {
-    struct aml_stream_out* out = (struct aml_stream_out*)stream;
-    struct aml_audio_device *adev = out->dev;
+int a2dp_out_get_status(struct aml_audio_device *adev) {
     struct aml_a2dp_hal * hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
-
-    if (hal == NULL) {
-        ALOGE("%s: a2dp hw is release", __func__);
+    if (!hal) {
+        AM_LOGW("a2dp_hal is null");
         return -1;
     }
+    return (int)hal->state;
+}
+
+int a2dp_out_set_parameters(struct aml_audio_device *adev, const char *kvpairs) {
+    struct aml_a2dp_hal * hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
+    R_CHECK_POINTER_LEGAL(-1, hal, "a2dp hw is released");
 
     std::unordered_map<std::string, std::string> params = ParseAudioParams(kvpairs);
     if (params.empty())
@@ -518,3 +653,18 @@ int a2dp_out_set_parameters (struct audio_stream *stream, const char *kvpairs) {
     return 0;
 }
 
+int a2dp_hal_dump(struct aml_audio_device *adev, int fd) {
+    struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal;
+    if (hal) {
+        dprintf(fd, "-------------[AM_HAL][A2DP]-------------\n");
+        dprintf(fd, "-[AML_HAL]      out_rate      : %10d     | out_ch    :%10d\n", hal->config.sample_rate, audio_channel_count_from_out_mask(hal->config.channel_mask));
+        dprintf(fd, "-[AML_HAL]      out_format    : %#10x     | cur_state :%10s\n", hal->config.format, a2dpStatus2String(hal->a2dphw.GetState()));
+        struct resample_para *resample = hal->resample;
+        if (resample) {
+            dprintf(fd, "-[AML_HAL] resample in_sr     : %10d     | out_sr    :%10d\n", resample->input_sr, resample->output_sr);
+            dprintf(fd, "-[AML_HAL] resample ch        : %10d\n", resample->channels);
+        }
+    }
+    return 0;
+}
+
diff --git a/audio/audio_hal/a2dp_hal.h b/audio/audio_hal/a2dp_hal.h
index afc7a1e..3102d80 100644
--- a/audio/audio_hal/a2dp_hal.h
+++ b/audio/audio_hal/a2dp_hal.h
@@ -24,14 +24,13 @@
 extern "C" {
 #endif
 
-int a2dp_out_open(struct audio_hw_device* stream);
-int a2dp_out_close(struct audio_hw_device* stream);
-int a2dp_out_resume(struct audio_stream_out* stream);
-int a2dp_out_standby(struct audio_stream* stream);
-ssize_t a2dp_out_write(struct audio_stream_out* stream, const void* buffer, size_t bytes);
-ssize_t a2dp_out_write_new(void *adev_ptr, void *hal_ptr, int is_tv_platform, int hal_rate, unsigned int flags, const void* buffer, size_t bytes); 
-uint32_t a2dp_out_get_latency(const struct audio_stream_out* stream);
-int a2dp_out_set_parameters (struct audio_stream *stream, const char *kvpairs);
+int a2dp_out_open(struct aml_audio_device *adev);
+int a2dp_out_close(struct aml_audio_device *adev);
+ssize_t a2dp_out_write(struct aml_audio_device *adev, audio_config_base_t *config, const void* buffer, size_t bytes);
+uint32_t a2dp_out_get_latency(struct aml_audio_device *adev);
+int a2dp_out_set_parameters (struct aml_audio_device *adev, const char *kvpairs);
+int a2dp_out_get_status(struct aml_audio_device *adev) ;
+int a2dp_hal_dump(struct aml_audio_device *adev, int fd);
 
 #ifdef __cplusplus
 }
diff --git a/audio/audio_hal/amlAudioMixer.c b/audio/audio_hal/amlAudioMixer.c
index 37bd172..0c68e3b 100644
--- a/audio/audio_hal/amlAudioMixer.c
+++ b/audio/audio_hal/amlAudioMixer.c
@@ -15,7 +15,7 @@
  */
 
 #define LOG_TAG "amlaudioMixer"
-//#define LOG_NDEBUG 0
+#define LOG_NDEBUG 0
 #define DEBUG_DUMP 0
 
 #define __USE_GNU
@@ -81,7 +81,6 @@ struct amlAudioMixer {
     uint32_t hwsync_frame_size;
     pthread_t out_mixer_tid;
     pthread_mutex_t lock;
-    pthread_mutex_t locks[NR_INPORTS];
     int exit_thread : 1;
     int mixing_enable : 1;
     enum mixer_state state;
@@ -145,18 +144,17 @@ int init_mixer_input_port(struct amlAudioMixer *audio_mixer,
         ALOGE("[%s:%d] NULL pointer", __func__, __LINE__);
         return -EINVAL;
     }
-
+    if (aml_out->inputPortID != -1) {
+       ALOGI("%s stream input port  id  %d exits delete it ",__FUNCTION__,aml_out->inputPortID);
+       delete_mixer_input_port(audio_mixer, aml_out->inputPortID);
+       aml_out->inputPortID = -1;
+    }
     /* if direct on, ie. the ALSA buffer is full, no need padding data anymore  */
-
-
-    pthread_mutex_lock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_DIRECT]);
     direct_on = (audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_DIRECT] != NULL);
-    pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_DIRECT]);
     port = new_input_port(MIXER_FRAME_COUNT, config, flags, volume, direct_on);
     port_index = mixer_get_inport_index(audio_mixer);
     LOG_ALWAYS_FATAL_IF(port_index > NR_INPORTS);
 
-    pthread_mutex_lock(&audio_mixer->locks[port_index]);
     if (audio_mixer->in_ports[port_index] != NULL) {
         ALOGW("[%s:%d] inport index:%s already exists! recreate", __func__, __LINE__, inportType2Str(port_index));
         free_input_port(audio_mixer->in_ports[port_index]);
@@ -177,7 +175,6 @@ int init_mixer_input_port(struct amlAudioMixer *audio_mixer,
         set_port_meta_data_cbk(port, on_meta_data_cbk, meta_data);
     }
     port->initial_frames = aml_out->frame_write_sum;
-    pthread_mutex_unlock(&audio_mixer->locks[port_index]);
     return 0;
 }
 
@@ -185,47 +182,30 @@ int delete_mixer_input_port(struct amlAudioMixer *audio_mixer,
         unsigned int port_index)
 {
     ALOGI("[%s:%d] input port:%d", __func__, __LINE__, port_index);
-    pthread_mutex_lock(&audio_mixer->locks[port_index]);
+    if (!is_inport_valid(port_index))
+        return -EINVAL;
+
     if (audio_mixer->in_ports[port_index]) {
+        pthread_mutex_lock(&audio_mixer->inport_lock);
         free_input_port(audio_mixer->in_ports[port_index]);
         audio_mixer->in_ports[port_index] = NULL;
         audio_mixer->inportsMasks &= ~(1 << port_index);
+        pthread_mutex_unlock(&audio_mixer->inport_lock);
     }
-    pthread_mutex_unlock(&audio_mixer->locks[port_index]);
     return 0;
 }
 
-void reset_mixer_all_input_port_cbk_data(struct amlAudioMixer *audio_mixer, void *data)
-{
-    size_t i = 0 ;
-    for (i = 0; i < NR_INPORTS; i++)
-    {
-        struct input_port *in_port = NULL;
-        pthread_mutex_lock(&audio_mixer->locks[i]);
-        in_port = audio_mixer->in_ports[i];
-        if (in_port && in_port->notify_cbk_data == data)
-        {
-            reset_port_cbk(in_port);
-        }
-        pthread_mutex_unlock(&audio_mixer->locks[i]);
-    }
-}
-
 int send_mixer_inport_message(struct amlAudioMixer *audio_mixer,
         aml_mixer_input_port_type_e port_index , enum PORT_MSG msg)
 {
-    int ret = 0;
-    struct input_port *port = NULL; 
-    pthread_mutex_lock(&audio_mixer->locks[port_index]);
-    port = audio_mixer->in_ports[port_index];
-    if (port) ret = send_inport_message(port, msg);
-    else
-    {
+    struct input_port *port = audio_mixer->in_ports[port_index];
+
+    if (port == NULL) {
         ALOGE("%s(), port index %d, inval", __func__, port_index);
-        ret = -EINVAL;
+        return -EINVAL;
     }
-    pthread_mutex_unlock(&audio_mixer->locks[port_index]);
-    return ret;
+
+    return send_inport_message(port, msg);
 }
 
 void set_mixer_hwsync_frame_size(struct amlAudioMixer *audio_mixer,
@@ -273,70 +253,62 @@ uint32_t get_mixer_inport_consumed_frames(
 int set_mixer_inport_volume(struct amlAudioMixer *audio_mixer,
         aml_mixer_input_port_type_e port_index, float vol)
 {
-    struct input_port *port = NULL; 
-    int ret = 0;
-    pthread_mutex_lock(&audio_mixer->locks[port_index]);
-    port = audio_mixer->in_ports[port_index];
+    struct input_port *port = audio_mixer->in_ports[port_index];
 
-    if (!port) 
-    {
-      ALOGE("%s(), NULL pointer", __func__);
-      ret = -EINVAL;
+    if (!port) {
+        ALOGE("%s(), NULL pointer", __func__);
+        return -EINVAL;
     }
-    else
-    {
-      if (vol > 1.0 || vol < 0) 
-      {
+
+    if (vol > 1.0 || vol < 0) {
         ALOGE("%s(), invalid vol %f", __func__, vol);
-        ret = -EINVAL;
-      }
-      else
-      {
-        set_inport_volume(port, vol);
-      }
+        return -EINVAL;
     }
-
-    pthread_mutex_unlock(&audio_mixer->locks[port_index]);
-    return ret;
+    set_inport_volume(port, vol);
+    return 0;
 }
 
 float get_mixer_inport_volume(struct amlAudioMixer *audio_mixer,
         aml_mixer_input_port_type_e port_index)
 {
-    float ret = 0;
-    struct input_port *port = NULL; 
-    pthread_mutex_lock(&audio_mixer->locks[port_index]);
-    port = audio_mixer->in_ports[port_index];
-    if (!port) ALOGE("%s(), NULL pointer", __func__);
-    else ret = get_inport_volume(port);
-    pthread_mutex_unlock(&audio_mixer->locks[port_index]);
-    return ret;
+    struct input_port *port = audio_mixer->in_ports[port_index];
+
+    if (!port) {
+        ALOGE("%s(), NULL pointer", __func__);
+        return 0;
+    }
+    return get_inport_volume(port);
 }
 
 int mixer_write_inport(struct amlAudioMixer *audio_mixer,
         unsigned int port_index, const void *buffer, int bytes)
 {
-    struct input_port *port = NULL; 
-    int written = 0; 
-    pthread_mutex_lock(&audio_mixer->locks[port_index]);
-    port = audio_mixer->in_ports[port_index];
+    struct input_port *port = audio_mixer->in_ports[port_index];
+    int             written = 0;
+    int64_t         cur_time_ns = 0;
+    struct timespec cur_timestamp;
 
     if (!port) 
     {
         ALOGE("%s(), NULL pointer", __func__);
-        written = -EINVAL;
+        return -EINVAL;
     }
-    else
-    {
 
-        written = port->write(port, buffer, bytes);
-        if (get_inport_state(port) != ACTIVE) {
-            ALOGI("[%s:%d] input port:%s is active now", __func__, __LINE__, inportType2Str(port->enInPortType));
-            set_inport_state(port, ACTIVE);
-        }
+    clock_gettime(CLOCK_MONOTONIC, &cur_timestamp);
+    cur_time_ns = (long long)cur_timestamp.tv_sec * 1000000000 + (long long)cur_timestamp.tv_nsec;
+    if (cur_time_ns - port->last_write_time_ns > port->buffer_len_ns) {
+        ALOGI("[%s:%d] input port:%s start write to input buffer", __func__, __LINE__, inportType2Str(port->enInPortType));
+        port->first_write = true;
     }
+    port->last_write_time_ns = cur_time_ns;
+
+    written = port->write(port, buffer, bytes);
+    if (get_inport_state(port) != ACTIVE) {
+        ALOGI("[%s:%d] input port:%s is active now", __func__, __LINE__, inportType2Str(port->enInPortType));
+        set_inport_state(port, ACTIVE);
+    }
+    
     ALOGV("%s(), signal line %d portIndex %d", __func__, __LINE__, port_index);
-    pthread_mutex_unlock(&audio_mixer->locks[port_index]);
     return written;
 }
 
@@ -344,38 +316,30 @@ int mixer_read_inport(struct amlAudioMixer *audio_mixer,
         unsigned int port_index, void *buffer, int bytes)
 {
     struct input_port *port = audio_mixer->in_ports[port_index];
-    if (port) return  port->read(port, buffer, bytes);
+    if (!port) {
+        ALOGE("%s(), NULL pointer", __func__);
+        return -EINVAL;
+    }
 
-    ALOGE("%s(), NULL pointer", __func__);
-    return -EINVAL;
+    return port->read(port, buffer, bytes);
 }
 
 //not used function
 int mixer_set_inport_state(struct amlAudioMixer *audio_mixer,
         aml_mixer_input_port_type_e port_index, enum port_state state)
 {
-    int ret = 0;
-    struct input_port *port = NULL; 
-    pthread_mutex_lock(&audio_mixer->locks[port_index]);
-    port = audio_mixer->in_ports[port_index];
-    if (!port) ret = -EINVAL;
-    else ret = set_inport_state(port, state);
-    pthread_mutex_unlock(&audio_mixer->locks[port_index]);
-    return ret;
+    struct input_port *port = audio_mixer->in_ports[port_index];
+
+    return set_inport_state(port, state);
 }
 
 //use used function
 enum port_state mixer_get_inport_state(struct amlAudioMixer *audio_mixer,
         aml_mixer_input_port_type_e port_index)
 {
-    enum port_state ret = IDLE;
-    struct input_port *port = NULL; 
-    //pthread_mutex_lock(&audio_mixer->locks[port_index]);
-    port = audio_mixer->in_ports[port_index];
-    if (!port) ALOGE("%s %d: no inport for index %d", __func__, __LINE__, (int)port_index);
-    else ret = get_inport_state(port);
-    //pthread_mutex_unlock(&audio_mixer->locks[port_index]);
-    return ret;
+    struct input_port *port = audio_mixer->in_ports[port_index];
+
+    return get_inport_state(port);
 }
 //TODO: handle message queue
 static void mixer_procs_msg_queue(struct amlAudioMixer *audio_mixer __unused)
@@ -452,63 +416,47 @@ int delete_mixer_output_port(struct amlAudioMixer *audio_mixer,
 
 static int mixer_output_write(struct amlAudioMixer *audio_mixer)
 {
+    struct aml_audio_device     *adev = audio_mixer->adev;
     enum MIXER_OUTPUT_PORT port_index = 0;
     struct output_port *out_port = audio_mixer->out_ports[port_index];
-    struct input_port *in_port_direct = NULL; 
-    struct input_port *in_port_system = NULL; 
     struct aml_stream_out *out = NULL;
-    struct aml_a2dp_hal *hal = NULL;
-    struct aml_audio_device *adev = NULL; 
-    int64_t elasp = 0; 
-    unsigned int hal_rate = 0;
-    int is_tv_platform = 0;
-    bool is_a2dp = false;
-    unsigned int flags = 0;
-
-    pthread_mutex_lock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_DIRECT]);
-    pthread_mutex_lock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]);
-
-    in_port_direct = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_DIRECT];
-    in_port_system = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_SYSTEM];
-
-    if (in_port_direct) pthread_mutex_lock(&in_port_direct->cbk_lock);
-    if (in_port_system) pthread_mutex_lock(&in_port_system->cbk_lock);
-
-    if (in_port_direct && in_port_direct->notify_cbk_data) {
-        out = (struct aml_stream_out *)in_port_direct->notify_cbk_data;
-    } else if (in_port_system && in_port_system->notify_cbk_data) {
-        out = (struct aml_stream_out *)in_port_system->notify_cbk_data;
-    }
-    out_port->sound_track_mode = audio_mixer->adev->sound_track_mode;
-    if (out)
-    {
-        is_a2dp = (out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP);
-        hal = out->dev->a2dp_hal;
-        is_tv_platform = out->is_tv_platform;
-        hal_rate = out->hal_rate;
-        flags = out->flags;
-        adev = out->dev;
+    struct input_port *in_port;
+    audio_config_base_t in_data_config = {48000, AUDIO_CHANNEL_OUT_STEREO, AUDIO_FORMAT_PCM_16_BIT};
+    unsigned int masks = 0;
+    pthread_mutex_lock(&audio_mixer->inport_lock);
+    masks = audio_mixer->inportsMasks;
+    while (masks) {
+        int i = 31 - __builtin_clz(masks);
+        masks &= ~(1 << i);
+        in_port = audio_mixer->in_ports[i];
+        if (NULL == in_port) {
+            continue;
+        }
+        if (in_port->enInPortType == AML_MIXER_INPUT_PORT_PCM_DIRECT && in_port->notify_cbk_data) {
+            out = (struct aml_stream_out *)in_port->notify_cbk_data;
+            break;
+        }
+        if ((in_port->enInPortType == AML_MIXER_INPUT_PORT_PCM_SYSTEM) && in_port->notify_cbk_data) {
+            out = (struct aml_stream_out *)in_port->notify_cbk_data;
+        }
+        if ((in_port->enInPortType == AML_MIXER_INPUT_PORT_PCM_MMAP) && (out == NULL) && in_port->notify_cbk_data) {
+            out = (struct aml_stream_out *)in_port->notify_cbk_data;
+        }
     }
+    pthread_mutex_unlock(&audio_mixer->inport_lock);
 
-    if (in_port_direct) pthread_mutex_unlock(&in_port_direct->cbk_lock);
-    if (in_port_system) pthread_mutex_unlock(&in_port_system->cbk_lock);
-
-    //NOTE: Please unlock mutex here or serious BT audio discontinous problem
-    pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_DIRECT]);
-    pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]);
-
-    while (is_output_data_avail(audio_mixer, port_index)) 
-    {
-        if (is_a2dp && adev)
-            a2dp_out_write_new(adev, hal, is_tv_platform, hal_rate, flags, out_port->data_buf, out_port->bytes_avail);
-        else {
-            pthread_mutex_lock(&audio_mixer->adev->alsa_pcm_lock);
-            out_port->write(out_port, out_port->data_buf, out_port->bytes_avail);
-            pthread_mutex_unlock(&audio_mixer->adev->alsa_pcm_lock);
-	}
+    out_port->sound_track_mode = audio_mixer->adev->sound_track_mode;
+    while (is_output_data_avail(audio_mixer, port_index)) {
+        // out_write_callbacks();
+        if (out && (adev->out_device & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+            a2dp_out_write(adev, &in_data_config, out_port->data_buf, out_port->bytes_avail);
+        } else {
+             pthread_mutex_lock(&audio_mixer->adev->alsa_pcm_lock);
+             out_port->write(out_port, out_port->data_buf, out_port->bytes_avail);
+             pthread_mutex_unlock(&audio_mixer->adev->alsa_pcm_lock);
+        }
         set_outport_data_avail(out_port, 0);
     }
-
     return 0;
 }
 
@@ -516,38 +464,45 @@ static int mixer_output_write(struct amlAudioMixer *audio_mixer)
 
 static int mixer_update_tstamp(struct amlAudioMixer *audio_mixer)
 {
-    struct input_port *in_port = NULL; 
     struct output_port *out_port = audio_mixer->out_ports[MIXER_OUTPUT_PORT_PCM];
+    struct input_port *in_port = NULL;
     unsigned int avail;
+    unsigned int masks = audio_mixer->inportsMasks;
     //struct timespec *timestamp;
 
-    pthread_mutex_lock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]);
-    in_port = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_SYSTEM];
+    while (masks) {
+        int i = 31 - __builtin_clz(masks);
+        masks &= ~(1 << i);
+        if (NULL == audio_mixer->in_ports[i]) {
+            continue;
+        }
+        if (audio_mixer->in_ports[i]->enInPortType == AML_MIXER_INPUT_PORT_PCM_SYSTEM) {
+            in_port = audio_mixer->in_ports[i];
+        }
 
-    /*only deal with system audio */
-    if (in_port == NULL || out_port == NULL)
-    {
-        pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]);
-        return 0;
-    }
+        /*only deal with system audio */
+        if (in_port == NULL || out_port == NULL)
+            continue;
+        if (out_port->pcm_handle == NULL)
+            continue;
 
-    if (pcm_get_htimestamp(out_port->pcm_handle, &avail, &in_port->timestamp) == 0) {
-        size_t kernel_buf_size = DEFAULT_KERNEL_FRAMES;
-        int64_t signed_frames = (int64_t)in_port->mix_consumed_frames - kernel_buf_size + avail;
-        if (signed_frames < 0) {
-            signed_frames = 0;
+        if (pcm_get_htimestamp(out_port->pcm_handle, &avail, &in_port->timestamp) == 0) {
+            size_t kernel_buf_size = DEFAULT_KERNEL_FRAMES;
+            int64_t signed_frames = in_port->mix_consumed_frames - kernel_buf_size + avail;
+            if (signed_frames < 0) {
+                signed_frames = 0;
+            }
+            in_port->presentation_frames = in_port->initial_frames + signed_frames;
+            ALOGV("%s() present frames:%lld, initial %lld, consumed %lld, sec:%ld, nanosec:%ld",
+                    __func__,
+                    in_port->presentation_frames,
+                    in_port->initial_frames,
+                    in_port->mix_consumed_frames,
+                    in_port->timestamp.tv_sec,
+                    in_port->timestamp.tv_nsec);
         }
-        in_port->presentation_frames = in_port->initial_frames + signed_frames;
-        ALOGV("%s() present frames:%lld, initial %lld, consumed %lld, sec:%ld, nanosec:%ld",
-                __func__,
-                in_port->presentation_frames,
-                in_port->initial_frames,
-                in_port->mix_consumed_frames,
-                in_port->timestamp.tv_sec,
-                in_port->timestamp.tv_nsec);
     }
 
-    pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]);
     return 0;
 }
 
@@ -560,7 +515,7 @@ static bool is_mixer_inports_ready(struct amlAudioMixer *audio_mixer)
         ALOGV("%s() port index %d, port ptr %p", __func__, port_index, in_port);
         if (in_port) {
             port_cnt++;
-            if (in_port->rbuf_ready(in_port)) {
+            if (in_port->rbuf_avail(in_port) >= in_port->data_len_bytes) {
                 ALOGV("port %d data ready", port_index);
                 ready++;
             } else {
@@ -616,8 +571,7 @@ static int update_inport_avail(struct input_port *in_port)
 {
     // first throw away the padding frames
     if (in_port->padding_frames > 0) {
-        if (in_port->data_buf_frame_cnt > in_port->padding_frames) in_port->padding_frames -= in_port->data_buf_frame_cnt;
-        else in_port->padding_frames = 0;
+        in_port->padding_frames -= in_port->data_buf_frame_cnt;
         set_inport_pts_valid(in_port, false);
     } else {
         in_port->mix_consumed_frames += in_port->data_buf_frame_cnt;
@@ -664,13 +618,11 @@ int mixer_flush_inport(struct amlAudioMixer *audio_mixer,
     int ret = 0;
     struct input_port *in_port = NULL;
     //NOTE: Do not lock here
-    //pthread_mutex_lock(&audio_mixer->locks[port_index]);
     in_port = audio_mixer->in_ports[port_index];
 
     if (!in_port) ret = -EINVAL;
     else ret = reset_input_port(in_port);
 
-    //pthread_mutex_unlock(&audio_mixer->locks[port_index]);
     return ret;
 }
 
@@ -678,16 +630,15 @@ static int mixer_inports_read(struct amlAudioMixer *audio_mixer)
 {
 
     unsigned int port_index = 0;
-    unsigned int masks = audio_mixer->inportsMasks;
- 
+    unsigned int masks = 0;
     ALOGV("++%s(), line %d", __func__, __LINE__);
+    pthread_mutex_lock(&audio_mixer->inport_lock);
+    masks = audio_mixer->inportsMasks;
     while (masks) {
         struct input_port *in_port;
         int ID = 31 - __builtin_clz(masks);
 
         masks &= ~(1 << ID);
-        
-        pthread_mutex_lock(&audio_mixer->locks[ID]);
         in_port = audio_mixer->in_ports[ID];
         if (in_port) {
             int ret = 0, fade_out = 0, fade_in = 0;
@@ -707,29 +658,36 @@ static int mixer_inports_read(struct amlAudioMixer *audio_mixer)
                     set_inport_state(in_port, ACTIVE);
                 } else if (state == STOPPED || state == PAUSED || state == FLUSHED) {
                     ALOGV("[%s:%d] input port:%s stopped, paused or flushed", __func__, __LINE__, inportType2Str(type));
-                    pthread_mutex_unlock(&audio_mixer->locks[ID]);
                     continue;
                 } else if (state == FLUSHING) {
                     mixer_flush_inport(audio_mixer, ID);
                     ALOGI("[%s:%d] input port:%s flushing->flushed", __func__, __LINE__, inportType2Str(type));
                     set_inport_state(in_port, FLUSHED);
-                    pthread_mutex_unlock(&audio_mixer->locks[ID]);
                     continue;
                 }
                 if (get_inport_state(in_port) == ACTIVE && in_port->data_valid) {
                     ALOGI("[%s:%d] input port:%s data already valid", __func__, __LINE__, inportType2Str(type));
-                    pthread_mutex_unlock(&audio_mixer->locks[ID]);
                     continue;
                 }
             } else {
                 if (in_port->data_valid) {
                     ALOGI("[%s:%d] input port ID:%d data already valid", __func__, __LINE__, ID);
-                    pthread_mutex_unlock(&audio_mixer->locks[ID]);
                     continue;
                 }
             }
 
-            if (in_port->rbuf_ready(in_port)) {
+            int input_avail_size = in_port->rbuf_avail(in_port);
+            ALOGV("[%s:%d] input port:%s, portId:%d, avail:%d, masks:%#x, inportsMasks:%#x, data_len_bytes:%d", __func__, __LINE__,
+                inportType2Str(type), ID, input_avail_size, masks, audio_mixer->inportsMasks, in_port->data_len_bytes);
+            if (input_avail_size >= in_port->data_len_bytes) {
+                if (in_port->first_write == true) {
+                    if (input_avail_size < in_port->inport_start_threshold) {
+                        continue;
+                    } else {
+                        ALOGI("[%s:%d] input port:%s first start, portId:%d, avail:%d", __func__, __LINE__, inportType2Str(type), ID, input_avail_size);
+                        in_port->first_write = false;
+                    }
+                }
                 ret = mixer_read_inport(audio_mixer, ID, in_port->data, in_port->data_len_bytes);
                 if (ret == (int)in_port->data_len_bytes) {
                     if (fade_out) {
@@ -760,10 +718,8 @@ static int mixer_inports_read(struct amlAudioMixer *audio_mixer)
                 }
             }
         }
-
-        pthread_mutex_unlock(&audio_mixer->locks[ID]);
     }
-
+    pthread_mutex_unlock(&audio_mixer->inport_lock);
     return 0;
 }
 
@@ -1120,10 +1076,11 @@ static int mixer_add_mixing_data(void *pMixedBuf, struct input_port *pInputPort,
 
 static int mixer_do_mixing_16bit(struct amlAudioMixer *audio_mixer)
 {
+    bool is_data_valid = false;
     struct input_port           *pstInputPort = NULL;
     struct output_port          *pstOutPort = audio_mixer->out_ports[MIXER_OUTPUT_PORT_PCM];
     struct aml_audio_device     *adev = audio_mixer->adev;
-    unsigned int masks = audio_mixer->inportsMasks;
+    unsigned int masks = 0;
 
     if (NULL == pstOutPort) {
         ALOGE("[%s:%d] outport is null", __func__, __LINE__);
@@ -1131,27 +1088,27 @@ static int mixer_do_mixing_16bit(struct amlAudioMixer *audio_mixer)
     }
 
     memset(audio_mixer->tmp_buffer, 0, MIXER_FRAME_COUNT * MIXER_OUT_FRAME_SIZE);
+    pthread_mutex_lock(&audio_mixer->inport_lock);
+    masks = audio_mixer->inportsMasks;
     while (masks) {
         struct input_port *in_port;
         int i = 31 - __builtin_clz(masks);
 
         masks &= ~(1 << i);
-        pthread_mutex_lock(&audio_mixer->locks[i]);
         pstInputPort = audio_mixer->in_ports[i];
         if (NULL == pstInputPort) {
-            pthread_mutex_unlock(&audio_mixer->locks[i]);
             continue;
         }
         if (0 == pstInputPort->data_valid) {
             if (adev->debug_flag) {
-                ALOGI("[%s:%d] inport:%s, but no valid data, maybe underrun", __func__, __LINE__, inportType2Str(i));
+                ALOGI("[%s:%d] inport:%s, but no valid data, maybe underrun", __func__, __LINE__, inportType2Str(pstInputPort->enInPortType));
             }
-            pthread_mutex_unlock(&audio_mixer->locks[i]);
             continue;
         }
+        is_data_valid = true;
         if (getprop_bool("vendor.media.audiohal.indump")) {
             char acFilePathStr[ENUM_TYPE_STR_MAX_LEN];
-            sprintf(acFilePathStr, "/data/audio/%s.pcm", inportType2Str(i));
+            sprintf(acFilePathStr, "/data/audio/%s_%d", inportType2Str(pstInputPort->enInPortType), pstInputPort->ID);
             aml_audio_dump_audio_bitstreams(acFilePathStr, pstInputPort->data, pstInputPort->data_len_bytes);
         }
         if (AML_MIXER_INPUT_PORT_PCM_DIRECT == pstInputPort->enInPortType) {
@@ -1162,13 +1119,23 @@ static int mixer_do_mixing_16bit(struct amlAudioMixer *audio_mixer)
                 pstInputPort->bytes_to_insert -= pstInputPort->data_len_bytes;
                 ALOGD("[%s:%d] PCM_DIRECT inport insert mute data, still need %zu, inserted length %zu", __func__, __LINE__,
                         pstInputPort->bytes_to_insert, pstInputPort->data_len_bytes);
-                pthread_mutex_unlock(&audio_mixer->locks[i]);
                 continue;
             }
         }
         mixer_add_mixing_data(audio_mixer->tmp_buffer, pstInputPort, pstOutPort);
-        pthread_mutex_unlock(&audio_mixer->locks[i]);
     }
+
+    /* only check the valid on a2dp case, normal alsa output we need continuous output,
+     * otherwise it will cause noise at the end
+     */
+    if (!is_data_valid && (adev->out_device & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+        if (adev->debug_flag) {
+            ALOGI("[%s:%d] inport no valid data", __func__, __LINE__);
+        }
+        pthread_mutex_unlock(&audio_mixer->inport_lock);
+        return -1;
+    }
+
     if (adev->is_TV) {
         apply_volume(adev->sink_gain[OUTPORT_SPEAKER], audio_mixer->tmp_buffer, sizeof(uint16_t),
             MIXER_FRAME_COUNT * pstOutPort->cfg.frame_size);
@@ -1194,6 +1161,7 @@ static int mixer_do_mixing_16bit(struct amlAudioMixer *audio_mixer)
         adev->wifi_audio_mode_started = false;
     }
     set_outport_data_avail(pstOutPort, MIXER_FRAME_COUNT * pstOutPort->cfg.frame_size);
+    pthread_mutex_unlock(&audio_mixer->inport_lock);
     return 0;
 }
 
@@ -1201,19 +1169,9 @@ int notify_mixer_input_avail(struct amlAudioMixer *audio_mixer)
 {
     aml_mixer_input_port_type_e port_index = 0;
     for (port_index = 0; port_index < AML_MIXER_INPUT_PORT_BUTT; port_index++) {
-        struct input_port *in_port = NULL; 
-        pthread_mutex_lock(&audio_mixer->locks[port_index]);
-        in_port = audio_mixer->in_ports[port_index];
-        if (in_port) 
-        {
-            pthread_mutex_lock(&in_port->cbk_lock);
-            if (in_port->on_input_avail_cbk)
-            {
-                in_port->on_input_avail_cbk(in_port->input_avail_cbk_data);
-            }
-            pthread_mutex_unlock(&in_port->cbk_lock);
-        }
-        pthread_mutex_unlock(&audio_mixer->locks[port_index]);
+        struct input_port *in_port = audio_mixer->in_ports[port_index];
+        if (in_port && in_port->on_input_avail_cbk)
+            in_port->on_input_avail_cbk(in_port->input_avail_cbk_data);
     }
 
     return 0;
@@ -1223,11 +1181,9 @@ int notify_mixer_exit(struct amlAudioMixer *audio_mixer)
 {
     aml_mixer_input_port_type_e port_index = 0;
     for (port_index = 0; port_index < AML_MIXER_INPUT_PORT_BUTT; port_index++) {
-        pthread_mutex_lock(&audio_mixer->locks[port_index]);
         struct input_port *in_port = audio_mixer->in_ports[port_index];
         if (in_port && in_port->on_notify_cbk)
             in_port->on_notify_cbk(in_port->notify_cbk_data);
-        pthread_mutex_unlock(&audio_mixer->locks[port_index]);
     }
 
     return 0;
@@ -1326,8 +1282,8 @@ static uint32_t get_mixer_inport_count(struct amlAudioMixer *audio_mixer)
 static void mixer_outport_feed_silence_frames(struct amlAudioMixer *audio_mixer)
 {
     struct output_port *out_port = get_outport(audio_mixer, MIXER_OUTPUT_PORT_PCM);
-    struct input_port *in_port_direct = NULL; 
-    struct input_port *in_port_system = NULL; 
+    struct input_port *in_port_direct = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_DIRECT];
+    struct input_port *in_port_system = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_SYSTEM];
     struct aml_stream_out *out = NULL;
 
     if (out_port == NULL) {
@@ -1341,22 +1297,12 @@ static void mixer_outport_feed_silence_frames(struct amlAudioMixer *audio_mixer)
     size_t bytes = frames * out_port->cfg.frame_size;
 
 
-    pthread_mutex_lock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_DIRECT]);
-    pthread_mutex_lock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]);
-    in_port_direct = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_DIRECT];
-    in_port_system = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_SYSTEM];
-
-
     if (in_port_direct && in_port_direct->notify_cbk_data) {
         out = (struct aml_stream_out *)in_port_direct->notify_cbk_data;
     } else if (in_port_system && in_port_system->notify_cbk_data) {
         out = (struct aml_stream_out *)in_port_system->notify_cbk_data;
     }
 
-
-    pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_DIRECT]);
-    pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]);
-
     /*for a2dp, we don't need feed silence data*/
     if (out && (out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP)) {
         return;
@@ -1422,14 +1368,15 @@ static void *mixer_16b_threadloop(void *data)
 uint32_t mixer_get_inport_latency_frames(struct amlAudioMixer *audio_mixer,
         aml_mixer_input_port_type_e port_index)
 {
-    struct input_port *port = NULL; 
-    uint32_t frames = 0;
-    pthread_mutex_lock(&audio_mixer->locks[port_index]);
-    port = audio_mixer->in_ports[port_index];
-    if (port) frames = port->get_latency_frames(port);
-    else ALOGE("%s(), NULL pointer", __func__);
-    pthread_mutex_unlock(&audio_mixer->locks[port_index]);
-    return frames;
+    struct input_port *port = audio_mixer->in_ports[port_index];
+    int written = 0;
+
+    if (!port) {
+        ALOGE("%s(), NULL pointer", __func__);
+        return 0;
+    }
+
+    return port->get_latency_frames(port);
 }
 
 int32_t mixer_get_outport_latency_frames(struct amlAudioMixer *audio_mixer)
@@ -1506,8 +1453,6 @@ struct amlAudioMixer *newAmlAudioMixer(
 {
     struct amlAudioMixer *audio_mixer = NULL;
     int ret = 0;
-    size_t i = 0;
-
     ALOGD("%s()", __func__);
 
     if (!pcm_handle) {
@@ -1530,19 +1475,17 @@ struct amlAudioMixer *newAmlAudioMixer(
     audio_mixer->frame_size_tmp = 2 * audio_bytes_per_sample(cfg.format);
 
     mixer_set_state(audio_mixer, MIXER_IDLE);
+    audio_mixer->adev = adev;
     ret = init_mixer_output_port(audio_mixer, pcm_handle,
             cfg, MIXER_FRAME_COUNT);
     if (ret < 0) {
         ALOGE("%s(), init mixer out port failed", __func__);
         goto err_state;
     }
-    audio_mixer->adev = adev;
     audio_mixer->inportsMasks = 0;
     audio_mixer->supportedInportsMasks = (1 << NR_INPORTS) - 1;
     pthread_mutex_init(&audio_mixer->lock, NULL);
-    for (i = 0 ; i < NR_INPORTS; i++) pthread_mutex_init(&audio_mixer->locks[i], NULL);
-
-
+    pthread_mutex_init(&audio_mixer->inport_lock, NULL);
     return audio_mixer;
 
 err_state:
@@ -1557,10 +1500,9 @@ err_tmp:
 
 void freeAmlAudioMixer(struct amlAudioMixer *audio_mixer)
 {
-    size_t i = 0;
     if (audio_mixer) {
         pthread_mutex_destroy(&audio_mixer->lock);
-        for (i = 0 ; i < NR_INPORTS; i++) pthread_mutex_destroy(&audio_mixer->locks[i]);
+        pthread_mutex_destroy(&audio_mixer->inport_lock);
         free(audio_mixer);
     }
 }
@@ -1580,29 +1522,38 @@ int mixer_get_presentation_position(
         uint64_t *frames,
         struct timespec *timestamp)
 {
+    pthread_mutex_lock(&audio_mixer->inport_lock);
+    struct input_port *port = NULL;
+
+    if (!frames || !timestamp) {
+        pthread_mutex_unlock(&audio_mixer->inport_lock);
+        return -EINVAL;
+    }
+
+    if (!is_inport_valid(port_index)) {
+        *frames = 0;
+        timestamp->tv_sec = 0;
+        timestamp->tv_nsec = 0;
+        pthread_mutex_unlock(&audio_mixer->inport_lock);
+        return -EINVAL;
+    }
 
-    int ret = 0;
-    struct input_port *port = NULL; 
-    pthread_mutex_lock(&audio_mixer->locks[port_index]);
     port = audio_mixer->in_ports[port_index];
-    if (port)
-    {
-      *frames = port->presentation_frames;
-      *timestamp = port->timestamp;
-      if (!is_inport_pts_valid(port)) 
-      {
-        ALOGW("%s(), not valid now", __func__);
-        ret = -EINVAL;
-      }
+    if (!port) {
+        ALOGW("%s(), port not ready now", __func__);
+        pthread_mutex_unlock(&audio_mixer->inport_lock);
+        return -EINVAL;
     }
-    else
-    {
-      ALOGW("%s(), port not ready now", __func__);
-      ret = -EINVAL;
+
+    *frames = port->presentation_frames;
+    *timestamp = port->timestamp;
+    if (!is_inport_pts_valid(port)) {
+        ALOGW("%s(), not valid now", __func__);
+        pthread_mutex_unlock(&audio_mixer->inport_lock);
+        return -EINVAL;
     }
-    pthread_mutex_unlock(&audio_mixer->locks[port_index]);
-    
-    return ret;
+    pthread_mutex_unlock(&audio_mixer->inport_lock);
+    return 0;
 }
 
 int mixer_set_padding_size(
@@ -1610,17 +1561,12 @@ int mixer_set_padding_size(
         aml_mixer_input_port_type_e port_index,
         int padding_bytes)
 {
-    int ret = 0;
-    struct input_port *port = NULL; 
-    pthread_mutex_lock(&audio_mixer->locks[port_index]);
-    port = audio_mixer->in_ports[port_index];
+    struct input_port *port = audio_mixer->in_ports[port_index];
     if (!port) {
         ALOGE("%s(), NULL pointer", __func__);
-        ret = -EINVAL;
+        return -EINVAL;
     }
-    ret = set_inport_padding_size(port, padding_bytes);
-    pthread_mutex_unlock(&audio_mixer->locks[port_index]);
-    return ret;
+    return set_inport_padding_size(port, padding_bytes);
 }
 
 int mixer_outport_pcm_restart(struct amlAudioMixer *audio_mixer)
diff --git a/audio/audio_hal/aml_audio_stream.h b/audio/audio_hal/aml_audio_stream.h
index 380a4e5..0543756 100755
--- a/audio/audio_hal/aml_audio_stream.h
+++ b/audio/audio_hal/aml_audio_stream.h
@@ -69,8 +69,13 @@ enum digital_format {
 enum stream_write_func {
     OUT_WRITE_NEW = 0,
     MIXER_AUX_BUFFER_WRITE_SM = 1,
-    MIXER_AUX_BUFFER_WRITE = 2,
-    MIXER_MAIN_BUFFER_WRITE = 3,
+    MIXER_MAIN_BUFFER_WRITE_SM = 2,
+    MIXER_MMAP_BUFFER_WRITE_SM = 3,
+    MIXER_AUX_BUFFER_WRITE = 4,
+    MIXER_MAIN_BUFFER_WRITE = 5,
+    MIXER_APP_BUFFER_WRITE = 6,
+    PROCESS_BUFFER_WRITE = 7,
+
     MIXER_WRITE_FUNC_MAX
 };
 
diff --git a/audio/audio_hal/aml_audio_timer.h b/audio/audio_hal/aml_audio_timer.h
index 74d7158..6b74b4c 100644
--- a/audio/audio_hal/aml_audio_timer.h
+++ b/audio/audio_hal/aml_audio_timer.h
@@ -20,6 +20,14 @@
 
 #include <stdint.h>
 
+#define MSEC_PER_SEC    1000L
+#define USEC_PER_MSEC   1000L
+#define NSEC_PER_USEC   1000L
+#define NSEC_PER_MSEC   1000000L
+#define USEC_PER_SEC    1000000L
+#define NSEC_PER_SEC    1000000000LL
+#define FSEC_PER_SEC    1000000000000000LL
+
 int aml_audio_sleep(uint64_t us);
 
 uint64_t aml_audio_get_systime(void);
diff --git a/audio/audio_hal/audio_hw.c b/audio/audio_hal/audio_hw.c
index 16193a8..47ea49a 100755
--- a/audio/audio_hal/audio_hw.c
+++ b/audio/audio_hal/audio_hw.c
@@ -160,28 +160,24 @@
 
 #define DISABLE_CONTINUOUS_OUTPUT "persist.vendor.audio.continuous.disable"
 
-#define ENUM_USECASE_TYPE_TO_STR(x, pStr)              ENUM_TYPE_TO_STR(x, strlen("STREAM_"), pStr)
+
 
 struct amlAudioMixer;
-extern void reset_mixer_all_input_port_cbk_data(struct amlAudioMixer *audio_mixer, void *data);
+//extern void reset_mixer_all_input_port_cbk_data(struct amlAudioMixer *audio_mixer, void *data);
 
-const char* usecase2Str(stream_usecase_t enUsecase)
+const char* usecase2Str(stream_usecase_t type)
 {
-    static char acTypeStr[ENUM_TYPE_STR_MAX_LEN];
-    char *pStr = "INVALID";
-    switch (enUsecase) {
-        ENUM_USECASE_TYPE_TO_STR(STREAM_PCM_NORMAL, pStr)
-        ENUM_USECASE_TYPE_TO_STR(STREAM_PCM_DIRECT, pStr)
-        ENUM_USECASE_TYPE_TO_STR(STREAM_PCM_HWSYNC, pStr)
-        ENUM_USECASE_TYPE_TO_STR(STREAM_RAW_DIRECT, pStr)
-        ENUM_USECASE_TYPE_TO_STR(STREAM_RAW_HWSYNC, pStr)
-        ENUM_USECASE_TYPE_TO_STR(STREAM_PCM_PATCH, pStr)
-        ENUM_USECASE_TYPE_TO_STR(STREAM_RAW_PATCH, pStr)
-        ENUM_USECASE_TYPE_TO_STR(STREAM_PCM_MMAP, pStr)
-        ENUM_USECASE_TYPE_TO_STR(STREAM_USECASE_MAX, pStr)
-    }
-    sprintf(acTypeStr, "[%d]%s", enUsecase, pStr);
-    return acTypeStr;
+    ENUM_TYPE_TO_STR_START("STREAM_");
+    ENUM_TYPE_TO_STR(STREAM_PCM_NORMAL)
+    ENUM_TYPE_TO_STR(STREAM_PCM_DIRECT)
+    ENUM_TYPE_TO_STR(STREAM_PCM_HWSYNC)
+    ENUM_TYPE_TO_STR(STREAM_RAW_DIRECT)
+    ENUM_TYPE_TO_STR(STREAM_RAW_HWSYNC)
+    ENUM_TYPE_TO_STR(STREAM_PCM_PATCH)
+    ENUM_TYPE_TO_STR(STREAM_RAW_PATCH)
+    ENUM_TYPE_TO_STR(STREAM_PCM_MMAP)
+    ENUM_TYPE_TO_STR(STREAM_USECASE_MAX)
+    ENUM_TYPE_TO_STR_END
 }
 
 static const struct pcm_config pcm_config_out = {
@@ -1200,10 +1196,6 @@ static int do_output_standby (struct aml_stream_out *out)
     int i = 0;
 
     ALOGD ("%s(%p)", __FUNCTION__, out);
-
-    if ((out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) && adev->a2dp_hal)
-        a2dp_out_standby(&out->stream.common);
-
     if (!out->standby) {
         //commit here for hwsync/mix stream hal mixer
         //pcm_close(out->pcm);
@@ -1270,10 +1262,6 @@ static int do_output_standby_direct (struct aml_stream_out *out)
     struct aml_audio_device *adev = out->dev;
 
     ALOGI ("%s,out %p, out->standby=%d", __FUNCTION__, out, out->standby);
-
-    if ((out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) && adev->a2dp_hal)
-        a2dp_out_standby(&out->stream.common);
-
     if (!out->standby) {
         if (out->buffer) {
             free (out->buffer);
@@ -4853,12 +4841,6 @@ static void adev_close_output_stream(struct audio_hw_device *dev,
         out->resample_outbuf = NULL;
     }
     pthread_mutex_unlock(&out->lock);
-
-    if (out->dev && out->dev->sm && out->dev->sm->mixerData)
-    {
-        reset_mixer_all_input_port_cbk_data(out->dev->sm->mixerData, out);
-    }
-
     free(stream);
     ALOGD("%s: exit", __func__);
 }
@@ -5143,12 +5125,19 @@ static int adev_set_parameters (struct audio_hw_device *dev, const char *kvpairs
             adev->a2dp_connect = 0;
             adev->out_device &= (~val);
             adev->out_devices &= (~val);
-            a2dp_out_close(dev);
+            a2dp_out_close(adev);
+            adev->bt_avrcp_supported = false;
             ALOGI("adev_set_parameters a2dp disconnect: %x, device=%x\n", val, adev->out_device);
         }
         goto exit;
     }
 
+    ret = str_parms_get_int(parms, "hal_param_bt_avrcp_supported", &val);
+    if (ret >= 0) {
+        adev->bt_avrcp_supported = (val != 0);
+        goto exit;
+    }
+
     // HDMI cable plug in
     ret = str_parms_get_int(parms, "connect", &val);
     if (ret >= 0) {
@@ -5168,7 +5157,7 @@ static int adev_set_parameters (struct audio_hw_device *dev, const char *kvpairs
             adev->a2dp_connect = 1;
             adev->out_device |= val;
             adev->out_devices |= val;
-            a2dp_out_open(dev);
+            a2dp_out_open(adev);
             ALOGI("adev_set_parameters a2dp connect: %x, device=%x\n", val, adev->out_device);
         }
         goto exit;
@@ -6539,7 +6528,6 @@ int do_output_standby_l(struct audio_stream *stream)
         if ((eDolbyMS12Lib == adev->dolby_lib_type) && (ms12->dolby_ms12_enable == true)) {
             get_dolby_ms12_cleanup(&adev->ms12);
         }
-        a2dp_out_standby(stream);
     }
 
     /*
@@ -7477,6 +7465,7 @@ ssize_t hw_write (struct audio_stream_out *stream
     ALOGV ("+%s() buffer %p bytes %zu", __func__, buffer, bytes);
     struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
     struct aml_audio_device *adev = aml_out->dev;
+    audio_config_base_t in_data_config = {48000, AUDIO_CHANNEL_OUT_STEREO, AUDIO_FORMAT_PCM_16_BIT};
     const uint16_t *tmp_buffer = buffer;
     int16_t *effect_tmp_buf = NULL;
     bool is_dtv = (adev->patch_src == SRC_DTV);
@@ -7490,6 +7479,11 @@ ssize_t hw_write (struct audio_stream_out *stream
     int  adjust_ms = 0;
     int  alsa_port = -1;
 
+    if (adev->is_TV && audio_is_linear_pcm(output_format)) {
+        in_data_config.channel_mask = AUDIO_CHANNEL_OUT_7POINT1;
+        in_data_config.format = AUDIO_FORMAT_PCM_32_BIT;
+    }
+
     adev->debug_flag = aml_audio_get_debug_flag();
     if (adev->debug_flag) {
         ALOGI("+%s() buffer %p bytes %zu, format %#x", __func__, buffer, bytes, output_format);
@@ -7660,7 +7654,7 @@ ssize_t hw_write (struct audio_stream_out *stream
                     while (adjust_bytes > 0) {
                         write_size = adjust_bytes > 1024 ? 1024 : adjust_bytes;
                         if (adev->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) {
-                            ret = a2dp_out_write(stream, (void*)buf, write_size);
+                            a2dp_out_write(adev, &in_data_config, (void*)buf, write_size);
                         } else {
                             ret = aml_alsa_output_write(stream, (void*)buf, write_size);
                         }
@@ -7683,7 +7677,7 @@ ssize_t hw_write (struct audio_stream_out *stream
             }
         }
         if (adev->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) {
-            ret = a2dp_out_write(stream, buffer, bytes);
+            a2dp_out_write(adev, &in_data_config, buffer, bytes);
         } else {
             ret = aml_alsa_output_write(stream, (void *) buffer, bytes);
         }
@@ -9499,6 +9493,7 @@ int adev_open_output_stream_new(struct audio_hw_device *dev,
                 }
                 ret = initSubMixingInput(aml_out, config);
                 aml_out->bypass_submix = false;
+                aml_out->inputPortID = -1;
                 if (ret < 0) {
                     ALOGE("initSub mixing input failed");
                 }
@@ -11174,6 +11169,13 @@ static int adev_set_audio_port_config (struct audio_hw_device *dev, const struct
                     case OUTPORT_HDMI_ARC:
                         aml_dev->sink_gain[outport] = 1.0;
                         break;
+                    case OUTPORT_A2DP:
+                        /* For scenarios that do not support AVRCP, audio_hal control is required. */
+                        aml_dev->sink_gain[outport] = DbToAmpl((float)(config->gain.values[0] / 100));
+                        if (aml_dev->bt_avrcp_supported && aml_dev->sink_gain[outport] > FLOAT_ZERO) {
+                            aml_dev->sink_gain[outport] = 1.0;
+                        }
+                        break;
                     case OUTPORT_SPEAKER:
                         aml_dev->sink_gain[outport] = DbToAmpl((float)(config->gain.values[0] / 100));
                         break;
@@ -11215,7 +11217,11 @@ static int adev_set_audio_port_config (struct audio_hw_device *dev, const struct
                     case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
                     case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
                         outport = OUTPORT_A2DP;
+                        /* For scenarios that do not support AVRCP, audio_hal control is required. */
                         aml_dev->sink_gain[outport] = DbToAmpl((float)(config->gain.values[0] / 100));
+                        if (aml_dev->bt_avrcp_supported && aml_dev->sink_gain[outport] > FLOAT_ZERO) {
+                            aml_dev->sink_gain[outport] = 1.0;
+                        }
                         break;
                 default:
                     ALOGE ("%s: invalid out device type %#x",
diff --git a/audio/audio_hal/audio_hw.h b/audio/audio_hal/audio_hw.h
index 698b8f1..9ea22b0 100644
--- a/audio/audio_hal/audio_hw.h
+++ b/audio/audio_hal/audio_hw.h
@@ -310,9 +310,10 @@ struct aml_audio_device {
     struct audio_config output_config;
     struct aml_arc_hdmi_desc hdmi_descs;
     int arc_hdmi_updated;
-    int a2dp_active;
     int a2dp_updated;
     void * a2dp_hal;
+    pthread_mutex_t a2dp_lock;
+    bool bt_avrcp_supported;
     int a2dp_connect;
     int hdmi_format_updated;
     struct aml_native_postprocess native_postprocess;
diff --git a/audio/audio_hal/audio_hw_utils.c b/audio/audio_hal/audio_hw_utils.c
index 0516638..2653701 100755
--- a/audio/audio_hal/audio_hw_utils.c
+++ b/audio/audio_hal/audio_hw_utils.c
@@ -47,6 +47,7 @@
 #include "alsa_device_parser.h"
 #include "a2dp_hal.h"
 #include "aml_audio_avsync_table.h"
+#include "dolby_lib_api.h"
 
 #ifdef LOG_NDEBUG_FUNCTION
 #define LOGFUNC(...) ((void)0)
@@ -782,7 +783,7 @@ uint32_t out_get_outport_latency(const struct audio_stream_out *stream)
     int frames = 0, latency_ms = 0;
 
     if (out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) {
-        return a2dp_out_get_latency(stream);
+        return a2dp_out_get_latency(adev);
     }
 
     if (is_stream_using_mixer(out)) {
@@ -809,6 +810,7 @@ static bool is_4x_rate_fmt(int codec_type)
 uint32_t out_get_latency_frames(const struct audio_stream_out *stream)
 {
     const struct aml_stream_out *out = (const struct aml_stream_out *)stream;
+    struct aml_audio_device *adev = out->dev;
     snd_pcm_sframes_t frames = 0;
     uint32_t whole_latency_frames;
     int ret = 0;
@@ -819,7 +821,10 @@ uint32_t out_get_latency_frames(const struct audio_stream_out *stream)
         mul = 4;
 
     if (out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) {
-        return a2dp_out_get_latency(stream)*out->hal_rate/1000;
+        if (eDolbyMS12Lib == adev->dolby_lib_type)
+            return a2dp_out_get_latency(adev)*48;
+        else
+            return a2dp_out_get_latency(adev)*out->hal_rate/1000;
     }
 
     whole_latency_frames = out->config.period_size * out->config.period_count;
@@ -836,6 +841,7 @@ uint32_t out_get_latency_frames(const struct audio_stream_out *stream)
 uint32_t out_get_alsa_latency_frames(const struct audio_stream_out *stream)
 {
     const struct aml_stream_out *out = (const struct aml_stream_out *)stream;
+    struct aml_audio_device *adev = out->dev;
     snd_pcm_sframes_t frames = 0;
     uint32_t whole_latency_frames;
     int ret = 0;
@@ -846,7 +852,10 @@ uint32_t out_get_alsa_latency_frames(const struct audio_stream_out *stream)
         mul = 4;
 
     if (out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) {
-        return a2dp_out_get_latency(stream)*out->hal_rate/1000;
+        if (eDolbyMS12Lib == adev->dolby_lib_type)
+            return a2dp_out_get_latency(adev)*48;
+        else
+            return a2dp_out_get_latency(adev)*out->hal_rate/1000;
     }
 
     whole_latency_frames = out->config.period_size * out->config.period_count / 2;
@@ -880,7 +889,7 @@ uint32_t out_get_ms12_latency_frames(const struct audio_stream_out *stream)
     }
 
     if (ms12_out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) {
-        return a2dp_out_get_latency(stream)*ms12_out->hal_rate/1000;
+        return a2dp_out_get_latency(adev)*48;
     }
 
     whole_latency_frames = config->start_threshold;
diff --git a/audio/audio_hal/audio_hw_utils.h b/audio/audio_hal/audio_hw_utils.h
index 78d5ba3..7316451 100644
--- a/audio/audio_hal/audio_hw_utils.h
+++ b/audio/audio_hal/audio_hw_utils.h
@@ -24,16 +24,57 @@
 #include "aml_audio_stream.h"
 
 #define ENUM_TYPE_STR_MAX_LEN                           (100)
+#define REPORT_DECODED_INFO  "/sys/class/amaudio/codec_report_info"
+#define AML_DEBUG_AUDIOINFO_REPORT_PROPERTY    "vendor.media.audio.info.report.debug"
+#define DUMP_AUDIO_INFO_DECODE (0x1000)  //use to enable the audio report info prop
 
-#define ENUM_TYPE_TO_STR(x, offset, pStr)                   \
-case x: {                                                   \
-    pStr = #x;                                              \
-    pStr += offset;                                         \
-    if (strlen(#x) - offset > 70) {                         \
-        pStr += 70;                                         \
+#define ENUM_TYPE_TO_STR_DEFAULT_STR            "INVALID_ENUM"
+#define ENUM_TYPE_TO_STR_START(prefix)                      \
+    const char *pStr = ENUM_TYPE_TO_STR_DEFAULT_STR;        \
+    int prefixLen = strlen(prefix);                         \
+    switch (type) {
+#define ENUM_TYPE_TO_STR(x)                                 \
+    case x:                                                 \
+        pStr = #x;                                          \
+        pStr += prefixLen;                                  \
+        if (strlen(#x) - prefixLen > 70) {                  \
+            pStr += 70;                                     \
+        }                                                   \
+        break;
+#define ENUM_TYPE_TO_STR_END                                \
+    default:                                                \
+        break;                                              \
     }                                                       \
-    break;                                                  \
-}
+    return pStr;
+
+#define AM_LOGV(fmt, ...)  ALOGV("[%s:%d] " fmt, __func__,__LINE__, ##__VA_ARGS__)
+#define AM_LOGD(fmt, ...)  ALOGD("[%s:%d] " fmt, __func__,__LINE__, ##__VA_ARGS__)
+#define AM_LOGI(fmt, ...)  ALOGI("[%s:%d] " fmt, __func__,__LINE__, ##__VA_ARGS__)
+#define AM_LOGW(fmt, ...)  ALOGW("[%s:%d] " fmt, __func__,__LINE__, ##__VA_ARGS__)
+#define AM_LOGE(fmt, ...)  ALOGE("[%s:%d] " fmt, __func__,__LINE__, ##__VA_ARGS__)
+
+#define R_CHECK_RET(ret, fmt, ...)                                                              \
+    if (ret != 0) {                                                                             \
+        AM_LOGE("ret:%d " fmt, ret, ##__VA_ARGS__);                                             \
+        return ret;                                                                             \
+    }
+
+#define NO_R_CHECK_RET(ret, fmt, ...)                                                           \
+    if (ret != 0) {                                                                             \
+        AM_LOGE("ret:%d " fmt, ret, ##__VA_ARGS__);                                             \
+    }
+
+#define R_CHECK_PARAM_LEGAL(ret, param, min, max, fmt, ...)                                     \
+    if ((int)param < min || param > max) {                                                           \
+        AM_LOGE("%s:%d is illegal, min:%d, max:%d " fmt, #param, param, min, max, ##__VA_ARGS__);\
+        return ret;                                                                             \
+    }
+ 
+#define R_CHECK_POINTER_LEGAL(ret, pointer, fmt, ...)                                           \
+    if (pointer == NULL) {                                                                      \
+        AM_LOGE("%s is null pointer " fmt, #pointer, ##__VA_ARGS__);                            \
+        return ret;                                                                             \
+    }
 
 int64_t aml_gettime(void);
 int get_sysfs_uint(const char *path, uint *value);
diff --git a/audio/audio_hal/audio_port.c b/audio/audio_hal/audio_port.c
index ce3212e..4640b98 100644
--- a/audio/audio_hal/audio_port.c
+++ b/audio/audio_hal/audio_port.c
@@ -32,21 +32,15 @@
 #define BUFF_CNT                    (4)
 #define SYS_BUFF_CNT                (4)
 
-#define ENUM_INPUT_PORT_TYPE_TO_STR(x, pStr)              ENUM_TYPE_TO_STR(x, strlen("AML_MIXER_INPUT_PORT_"), pStr)
-
-const char *inportType2Str(aml_mixer_input_port_type_e enInportType)
-{
-    static char acTypeStr[ENUM_TYPE_STR_MAX_LEN];
-    char *pStr = "INVALID";
-    switch (enInportType) {
-        ENUM_INPUT_PORT_TYPE_TO_STR(AML_MIXER_INPUT_PORT_INVAL, pStr)
-        ENUM_INPUT_PORT_TYPE_TO_STR(AML_MIXER_INPUT_PORT_PCM_SYSTEM, pStr)
-        ENUM_INPUT_PORT_TYPE_TO_STR(AML_MIXER_INPUT_PORT_PCM_DIRECT, pStr)
-        ENUM_INPUT_PORT_TYPE_TO_STR(AML_MIXER_INPUT_PORT_PCM_MMAP, pStr)
-        ENUM_INPUT_PORT_TYPE_TO_STR(AML_MIXER_INPUT_PORT_BUTT, pStr)
-    }
-    sprintf(acTypeStr, "[%d]%s", enInportType, pStr);
-    return acTypeStr;
+const char* inportType2Str(aml_mixer_input_port_type_e type)
+{
+    ENUM_TYPE_TO_STR_START("AML_MIXER_INPUT_PORT_");
+    ENUM_TYPE_TO_STR(AML_MIXER_INPUT_PORT_INVAL)
+    ENUM_TYPE_TO_STR(AML_MIXER_INPUT_PORT_PCM_SYSTEM)
+    ENUM_TYPE_TO_STR(AML_MIXER_INPUT_PORT_PCM_DIRECT)
+    ENUM_TYPE_TO_STR(AML_MIXER_INPUT_PORT_PCM_MMAP)
+    ENUM_TYPE_TO_STR(AML_MIXER_INPUT_PORT_BUTT)
+    ENUM_TYPE_TO_STR_END
 }
 
 static ssize_t input_port_write(struct input_port *port, const void *buffer, int bytes)
@@ -82,7 +76,7 @@ int inport_buffer_level(struct input_port *port)
     return get_buffer_read_space(port->r_buf);
 }
 
-bool ring_buf_ready(struct input_port *port)
+int get_inport_avail_size(struct input_port *port)
 {
     int read_avail = get_buffer_read_space(port->r_buf);
 
@@ -91,7 +85,7 @@ bool ring_buf_ready(struct input_port *port)
             __func__, port->enInPortType, read_avail, port->data_len_bytes);
     }
 
-    return (read_avail >= (int)port->data_len_bytes);
+    return read_avail;
 }
 
 bool is_direct_flags(audio_output_flags_t flags) {
@@ -312,6 +306,11 @@ struct input_port *new_input_port(
         ALOGE("init ring buffer fail, buffer_size = %d", input_port_rbuf_size);
         goto err_rbuf_init;
     }
+    port->inport_start_threshold = 0;
+    /* increase the input size to prevent underrun */
+    if (enPortType == AML_MIXER_INPUT_PORT_PCM_MMAP) {
+        port->inport_start_threshold = input_port_rbuf_size / 2;
+    }
 
     port->enInPortType = enPortType;
     //port->format = config->format;
@@ -320,9 +319,12 @@ struct input_port *new_input_port(
     port->data = data;
     port->data_buf_frame_cnt = buf_frames;
     port->data_len_bytes = thunk_size;
+    port->buffer_len_ns = (input_port_rbuf_size / port->cfg.frame_size) * 1000000000LL / port->cfg.sampleRate;
+    port->first_write = true;
+    port->last_write_time_ns = 0;
     port->read = input_port_read;
     port->write = input_port_write;
-    port->rbuf_ready = ring_buf_ready;
+    port->rbuf_avail = get_inport_avail_size;
     port->get_latency_frames = inport_get_latency_frames;
     port->port_status = STOPPED;
     port->is_hwsync = false;
diff --git a/audio/audio_hal/audio_port.h b/audio/audio_hal/audio_port.h
index 90977b8..e0be4ce 100644
--- a/audio/audio_hal/audio_port.h
+++ b/audio/audio_hal/audio_port.h
@@ -87,6 +87,7 @@ struct input_port {
     char *data;                             /* input port temp buffer. */
     size_t data_buf_frame_cnt;              /* input port temp buffer, data frames for one cycle. */
     size_t data_len_bytes;                  /* input port temp buffer, data size for one cycle. */
+    int64_t buffer_len_ns;                   /* input port temp buffer, input buffer size, the unit is ns. */
 
     int data_valid;
     size_t bytes_to_insert;                 /* insert 0 data count index. Units: Byte */
@@ -97,7 +98,7 @@ struct input_port {
     ssize_t (*write)(struct input_port *port, const void *buffer, int bytes);
     ssize_t (*read)(struct input_port *port, void *buffer, int bytes);
     uint32_t (*get_latency_frames)(struct input_port *port);
-    bool (*rbuf_ready)(struct input_port *port);
+    int (*rbuf_avail)(struct input_port *port);
     void *notify_cbk_data;
     int (*on_notify_cbk)(void *data);
     void *input_avail_cbk_data;
@@ -117,6 +118,9 @@ struct input_port {
     uint64_t presentation_frames;
     int padding_frames;
     bool pts_valid;
+    bool        first_write;
+    int         inport_start_threshold;
+    int64_t     last_write_time_ns;
     pthread_mutex_t cbk_lock;
 };
 
@@ -199,6 +203,6 @@ int set_inport_pts_valid(struct input_port *in_port, bool valid);
 bool is_inport_pts_valid(struct input_port *in_port);
 void outport_pcm_restart(struct output_port *port);
 
-const char *inportType2Str(aml_mixer_input_port_type_e enInportType);
+const char *inportType2Str(aml_mixer_input_port_type_e type);
 
 #endif /* _AUDIO_PORT_H_ */
diff --git a/audio/audio_hal/sub_mixing_factory.c b/audio/audio_hal/sub_mixing_factory.c
index baa175a..ee6d2bc 100755
--- a/audio/audio_hal/sub_mixing_factory.c
+++ b/audio/audio_hal/sub_mixing_factory.c
@@ -1,6 +1,6 @@
 
 #define LOG_TAG "audio-subMixingFactory"
-//#define LOG_NDEBUG 0
+#define LOG_NDEBUG 0
 #define __USE_GNU
 
 #include <errno.h>
@@ -109,7 +109,9 @@ static int initSubMixngOutput(
     }
     return 0;
 err:
-    pcm_close(pcm);
+    if (pcm != NULL) {
+        pcm_close(pcm);
+    }
     return res;
 };
 
@@ -171,7 +173,7 @@ static ssize_t aml_out_write_to_mixer(struct audio_stream_out *stream, const voi
 
         //usleep((bytes- written_total) * 1000 / 5 / 48);
         //if (out->port_index == 1) {
-            ts_wait_time_us(&ts, 1000);
+            ts_wait_time_us(&ts, 5000);
             ALOGV("-%s() wait....", __func__);
             pthread_mutex_lock(&out->cond_lock);
             pthread_cond_timedwait(&out->cond, &out->cond_lock, &ts);
@@ -313,7 +315,7 @@ exit:
         //TODO
         if (out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP)
             latency_frames = mixer_get_inport_latency_frames(audio_mixer, out->inputPortID)
-		+ a2dp_out_get_latency(stream) * out->hal_rate / 1000;
+                    + a2dp_out_get_latency(adev) * out->hal_rate / 1000;
         else
         {
             int outport_latency_frame = mixer_get_outport_latency_frames(audio_mixer);
@@ -779,7 +781,8 @@ static int deleteSubMixingInputPcm(struct aml_stream_out *out)
 
     ALOGI("%s(), cnt_stream_using_mixer %d",
             __func__, sm->cnt_stream_using_mixer);
-    //delete_mixer_input_port(audio_mixer, out->port_index);
+    delete_mixer_input_port(audio_mixer, out->inputPortID);
+    out->inputPortID = -1;
 
     struct meta_data_list *mdata_list;
     struct listnode *item;
@@ -1119,15 +1122,10 @@ ssize_t mixer_aux_buffer_write_sm(struct audio_stream_out *stream, const void *b
     }
 
     if (adev->debug_flag) {
-        ALOGD("[%s:%d] stream:%p, out_device:%#x, bytes:%d, a2dp_active=%d, out->flags=0x%x,hal_internal_format=0x%x", __func__, __LINE__,
-            stream, aml_out->out_device, bytes, adev->a2dp_active, aml_out->flags, aml_out->hal_internal_format);
+        ALOGD("[%s:%d] stream:%p, out_device:%#x, bytes:%d, out->flags=0x%x,hal_internal_format=0x%x", __func__, __LINE__,
+            stream, aml_out->out_device, bytes, aml_out->flags, aml_out->hal_internal_format);
     }
 
-    if ((aml_out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) && (adev->a2dp_active == 1)
-		&& (aml_out->hal_internal_format != AUDIO_FORMAT_PCM_16_BIT)) {
-        //aml_hw_mixer_write(&adev->hw_mixer, buffer, bytes);
-        goto exit;
-    }
     if (adev->out_device != aml_out->out_device) {
         ALOGD("[%s:%d] stream:%p, switch from device:%#x to device:%#x", __func__, __LINE__,
              stream, adev->out_device, aml_out->out_device);
@@ -1142,6 +1140,8 @@ ssize_t mixer_aux_buffer_write_sm(struct audio_stream_out *stream, const void *b
     if (aml_out->standby) {
         char *padding_buf = NULL;
         int padding_bytes = 512 * 4 * 8;
+        if (aml_out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP)
+            padding_bytes = 0;
 
         //set_thread_affinity();
         init_mixer_input_port(sm->mixerData, &aml_out->audioCfg, aml_out->flags,
@@ -1201,8 +1201,8 @@ exit:
 
 
     if (aml_out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) {
-        uint64_t latency_frames = mixer_get_inport_latency_frames(sm->mixerData, aml_out->enInputPortType)
-                + a2dp_out_get_latency(stream) * aml_out->hal_rate / 1000;
+        uint64_t latency_frames = mixer_get_inport_latency_frames(sm->mixerData, aml_out->inputPortID)
+                + a2dp_out_get_latency(adev) * aml_out->hal_rate / 1000;
         if (aml_out->frame_write_sum > latency_frames)
             aml_out->last_frames_postion = aml_out->frame_write_sum - latency_frames;
         else
@@ -1353,9 +1353,11 @@ static int usecase_change_validate_l_sm(struct aml_stream_out *aml_out, bool is_
         }
     } else if (STREAM_PCM_MMAP == aml_out->usecase) {
         aml_out->write = mixer_mmap_buffer_write_sm;
+        aml_out->write_func = MIXER_MMAP_BUFFER_WRITE_SM;
         ALOGI("%s(), mixer_mmap_buffer_write_sm !", __FUNCTION__);
     } else {
         aml_out->write = mixer_main_buffer_write_sm;
+        aml_out->write_func = MIXER_MAIN_BUFFER_WRITE_SM;
         ALOGI("%s(), mixer_main_buffer_write_sm !", __FUNCTION__);
     }
 
@@ -1440,9 +1442,7 @@ int out_standby_subMixingPCM(struct audio_stream *stream)
     aml_out->status = STREAM_STANDBY;
     aml_out->standby = true;
     delete_mixer_input_port(audio_mixer, aml_out->inputPortID);
-
-    if ((aml_out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) && adev->a2dp_hal)
-        a2dp_out_standby(stream);
+    aml_out->inputPortID = -1;
 
     if (aml_out->hwsync_extractor) {
         delete_hw_avsync_header_extractor(aml_out->hwsync_extractor);
@@ -1484,8 +1484,6 @@ static int out_pause_subMixingPCM(struct audio_stream_out *stream)
     send_mixer_inport_message(audio_mixer, aml_out->inputPortID, MSG_PAUSE);
 
     aml_out->pause_status = true;
-    if (aml_out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP)
-        a2dp_out_standby(&stream->common);
     ALOGI("-%s()", __func__);
     return 0;
 }
@@ -1607,13 +1605,11 @@ int switchNormalStream(struct aml_stream_out *aml_out, bool on)
         aml_out->stream.write = out_write_subMixingPCM;
         aml_out->stream.common.standby = out_standby_subMixingPCM;
         out_standby_subMixingPCM((struct audio_stream *)aml_out);
-        aml_out->write_func = MIXER_AUX_BUFFER_WRITE_SM;
     } else {
         aml_out->stream.write = out_write_new;//mixer_aux_buffer_write;
         aml_out->stream.common.standby = out_standby_new;
         deleteSubMixingInputPcm(aml_out);
         out_standby_new((struct audio_stream *)aml_out);
-        aml_out->write_func = OUT_WRITE_NEW;
     }
 
     return 0;
diff --git a/audio/utils/aml_malloc_debug.c b/audio/utils/aml_malloc_debug.c
index 5c3dde4..ea3698f 100644
--- a/audio/utils/aml_malloc_debug.c
+++ b/audio/utils/aml_malloc_debug.c
@@ -247,3 +247,25 @@ void aml_audio_debug_malloc_showinfo(uint32_t level)
 
     return;
 }
+
+int aml_audio_check_and_realloc(void** pointer, size_t* cur_size, size_t need_size)
+{
+    if (pointer == NULL || cur_size == NULL) {
+        ALOGE("[%s:%d] pointer:%p or cur_size:%p is null", __func__, __LINE__, pointer, cur_size);
+        return -1;
+    }
+
+    if (*cur_size < need_size || *pointer == NULL) {
+        void *p = aml_audio_realloc(*pointer, need_size);
+        if (p == NULL) {
+            ALOGE("[%s:%d] realloc buffer failed size:%zu", __func__, __LINE__, need_size);
+            return -ENOMEM;
+        } else {
+            memset(p, 0, need_size);
+            *pointer = p;
+        }
+        *cur_size = need_size;
+    }
+    return 0;
+}
+
diff --git a/audio/utils/include/aml_malloc_debug.h b/audio/utils/include/aml_malloc_debug.h
index df689f1..99c44fe 100644
--- a/audio/utils/include/aml_malloc_debug.h
+++ b/audio/utils/include/aml_malloc_debug.h
@@ -41,5 +41,6 @@ void* aml_audio_debug_realloc(void* pointer, size_t bytes, char * file_name, uin
 void* aml_audio_debug_calloc(size_t nmemb, size_t bytes, char * file_name, uint32_t line);
 void aml_audio_debug_free(void* pointer);
 void aml_audio_debug_malloc_showinfo(uint32_t level);
+int aml_audio_check_and_realloc(void** pointer, size_t* cur_size, size_t need_size);
 
 #endif
-- 
2.17.1

(SW) Sam Yang

2023-12-21 15:19

developer   ~0014801

Hi JynGyu,

done, the commit is: 2023-12-21 15:14:13 | Sh.Yu@amlogic.com | eea9d436 | hardware/amlogic | [BPM-27223] audio_hal: play youtube with a2dp audio breadk [1/1]

Thanks~
Sam

(ALTech) JunGyu Kim

2023-12-27 14:13

developer   ~0014822

This issue was fixed by Amlogic.
I close this issue.

Thank you.
Kim

Issue History

Date Modified Username Field Change
2023-08-17 17:06 (ALTech) JunGyu Kim New Issue
2023-08-17 17:06 (ALTech) JunGyu Kim Status new => assigned
2023-08-17 17:06 (ALTech) JunGyu Kim Assigned To => (SW) Kerwin Chen
2023-08-17 17:06 (ALTech) JunGyu Kim File Added: BTVV-6562.zip
2023-08-17 17:06 (ALTech) JunGyu Kim Issue Monitored: (ALTech) SY Yoon
2023-08-17 17:06 (ALTech) JunGyu Kim Issue Monitored: (ALTech) Younkwang Jung
2023-08-18 09:29 (SW) Jason Ling Assigned To (SW) Kerwin Chen => (SW) Sam Yang
2023-08-22 08:09 (ALTech) Younkwang Jung Note Added: 0013930
2023-08-22 12:21 (SW) Jason Ling Note Added: 0013935
2023-08-22 13:29 (ALTech) JunGyu Kim Note Added: 0013936
2023-08-22 15:11 (SW) Sam Yang Issue Monitored: (SW) Sam Yang
2023-08-28 09:28 (ALTech) Younkwang Jung Note Added: 0013997
2023-08-29 11:16 (SW) Sam Yang Note Added: 0014013
2023-09-06 10:20 (ALTech) Younkwang Jung Note Added: 0014085
2023-09-06 10:22 (SW) Sam Yang Note Added: 0014086
2023-09-06 10:22 (SW) Sam Yang Assigned To (SW) Sam Yang => (ALTech) Younkwang Jung
2023-09-06 10:22 (SW) Sam Yang Status assigned => feedback
2023-09-06 19:27 (ALTech) JunGyu Kim Note Added: 0014098
2023-09-06 19:27 (ALTech) JunGyu Kim Status feedback => assigned
2023-09-07 15:17 (SW) Sam Yang Note Added: 0014104
2023-09-26 14:34 (ALTech) JunGyu Kim Note Added: 0014222
2023-09-26 14:34 (ALTech) JunGyu Kim File Added: btsnoop_hci.log
2023-10-11 17:12 (ALTech) Younkwang Jung Note Added: 0014266
2023-10-11 17:35 (SW) Sam Yang Note Added: 0014267
2023-10-11 18:54 (SW) Sam Yang Note Edited: 0014267
2023-10-12 07:56 (ALTech) Younkwang Jung Note Added: 0014269
2023-10-12 09:31 (SW) Sam Yang Note Added: 0014272
2023-10-12 09:31 (SW) Sam Yang File Added: audioData.wav
2023-12-21 09:22 (ALTech) JunGyu Kim Note Added: 0014792
2023-12-21 15:13 (ALTech) Younkwang Jung Note Added: 0014800
2023-12-21 15:13 (ALTech) Younkwang Jung File Added: image.png
2023-12-21 15:13 (ALTech) Younkwang Jung File Added: 0001-audio_hal-play-youtube-with-a2dp-audio-breadk-1-1.patch
2023-12-21 15:19 (SW) Sam Yang Note Added: 0014801
2023-12-21 15:20 (SW) Sam Yang Status assigned => resolved
2023-12-21 15:20 (SW) Sam Yang Resolution open => fixed
2023-12-27 14:13 (ALTech) JunGyu Kim Status resolved => closed
2023-12-27 14:13 (ALTech) JunGyu Kim Note Added: 0014822